@jmruthers/pace-core 0.2.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +202 -0
- package/README.md +299 -0
- package/dist/DataTable-BHlzyKZP.d.ts +116 -0
- package/dist/DataTable-GEY5U7OI.js +100 -0
- package/dist/DataTable-GEY5U7OI.js.map +1 -0
- package/dist/PublicLoadingSpinner-DztrzuJr.d.ts +3430 -0
- package/dist/UnifiedAuthProvider-w66zSCUf.d.ts +160 -0
- package/dist/api-GZHIDA4X.js +41 -0
- package/dist/api-GZHIDA4X.js.map +1 -0
- package/dist/appConfig-BVGyuvI7.d.ts +71 -0
- package/dist/appNameResolver-7GHF5ED2.js +22 -0
- package/dist/appNameResolver-7GHF5ED2.js.map +1 -0
- package/dist/audit-BUW3LMJB.js +16 -0
- package/dist/audit-BUW3LMJB.js.map +1 -0
- package/dist/chunk-22KLBHPS.js +29 -0
- package/dist/chunk-22KLBHPS.js.map +1 -0
- package/dist/chunk-24MKLB7U.js +81 -0
- package/dist/chunk-24MKLB7U.js.map +1 -0
- package/dist/chunk-2MKP6IYD.js +388 -0
- package/dist/chunk-2MKP6IYD.js.map +1 -0
- package/dist/chunk-2V3Y6YBC.js +114 -0
- package/dist/chunk-2V3Y6YBC.js.map +1 -0
- package/dist/chunk-5CDJCTOO.js +190 -0
- package/dist/chunk-5CDJCTOO.js.map +1 -0
- package/dist/chunk-6ZQVSHKL.js +1345 -0
- package/dist/chunk-6ZQVSHKL.js.map +1 -0
- package/dist/chunk-74C6SNEC.js +77 -0
- package/dist/chunk-74C6SNEC.js.map +1 -0
- package/dist/chunk-7BNPOCLL.js +178 -0
- package/dist/chunk-7BNPOCLL.js.map +1 -0
- package/dist/chunk-7JL3T7BO.js +3344 -0
- package/dist/chunk-7JL3T7BO.js.map +1 -0
- package/dist/chunk-CDQ3PX7L.js +18 -0
- package/dist/chunk-CDQ3PX7L.js.map +1 -0
- package/dist/chunk-DY5E3AT7.js +1734 -0
- package/dist/chunk-DY5E3AT7.js.map +1 -0
- package/dist/chunk-ETEJVKYK.js +6032 -0
- package/dist/chunk-ETEJVKYK.js.map +1 -0
- package/dist/chunk-I5Z3QH5X.js +32 -0
- package/dist/chunk-I5Z3QH5X.js.map +1 -0
- package/dist/chunk-MZBUOP4P.js +119 -0
- package/dist/chunk-MZBUOP4P.js.map +1 -0
- package/dist/chunk-N2EUGZRW.js +98 -0
- package/dist/chunk-N2EUGZRW.js.map +1 -0
- package/dist/chunk-NQ4TOOO6.js +20 -0
- package/dist/chunk-NQ4TOOO6.js.map +1 -0
- package/dist/chunk-OHXGNT3K.js +21 -0
- package/dist/chunk-OHXGNT3K.js.map +1 -0
- package/dist/chunk-OKXMUYIB.js +522 -0
- package/dist/chunk-OKXMUYIB.js.map +1 -0
- package/dist/chunk-PFRRIDYA.js +382 -0
- package/dist/chunk-PFRRIDYA.js.map +1 -0
- package/dist/chunk-PLDDJCW6.js +49 -0
- package/dist/chunk-PLDDJCW6.js.map +1 -0
- package/dist/chunk-SS3E6QLB.js +695 -0
- package/dist/chunk-SS3E6QLB.js.map +1 -0
- package/dist/chunk-TMRLB2LA.js +326 -0
- package/dist/chunk-TMRLB2LA.js.map +1 -0
- package/dist/chunk-WYB6MBZA.js +5533 -0
- package/dist/chunk-WYB6MBZA.js.map +1 -0
- package/dist/chunk-YDJW5XTN.js +84 -0
- package/dist/chunk-YDJW5XTN.js.map +1 -0
- package/dist/components.d.ts +1308 -0
- package/dist/components.js +3759 -0
- package/dist/components.js.map +1 -0
- package/dist/database-C3Szpi5J.d.ts +470 -0
- package/dist/hooks.d.ts +449 -0
- package/dist/hooks.js +612 -0
- package/dist/hooks.js.map +1 -0
- package/dist/index.d.ts +385 -0
- package/dist/index.js +569 -0
- package/dist/index.js.map +1 -0
- package/dist/organisation-CO3Sh3_D.d.ts +99 -0
- package/dist/providers.d.ts +45 -0
- package/dist/providers.js +36 -0
- package/dist/providers.js.map +1 -0
- package/dist/rbac/eslint-rules.d.ts +52 -0
- package/dist/rbac/eslint-rules.js +252 -0
- package/dist/rbac/eslint-rules.js.map +1 -0
- package/dist/rbac/index.d.ts +1918 -0
- package/dist/rbac/index.js +2212 -0
- package/dist/rbac/index.js.map +1 -0
- package/dist/styles/core.css +401 -0
- package/dist/styles/fonts/georama-italic.woff2 +0 -0
- package/dist/styles/fonts/georama.woff2 +0 -0
- package/dist/styles/fonts/open-sans-italic.woff2 +0 -0
- package/dist/styles/fonts/open-sans.woff2 +0 -0
- package/dist/styles/fonts/reddit-mono.woff2 +0 -0
- package/dist/styles/index.d.ts +36 -0
- package/dist/styles/index.js +24 -0
- package/dist/styles/index.js.map +1 -0
- package/dist/theming/runtime.d.ts +73 -0
- package/dist/theming/runtime.js +16 -0
- package/dist/theming/runtime.js.map +1 -0
- package/dist/types-CInEi-ng.d.ts +316 -0
- package/dist/types.d.ts +196 -0
- package/dist/types.js +83 -0
- package/dist/types.js.map +1 -0
- package/dist/unified-CM7T0aTK.d.ts +198 -0
- package/dist/useComponentPerformance-DE9l5RkL.d.ts +11 -0
- package/dist/usePublicRouteParams-B6i0KtXW.d.ts +477 -0
- package/dist/utils.d.ts +639 -0
- package/dist/utils.js +1103 -0
- package/dist/utils.js.map +1 -0
- package/dist/validation-PM_iOaTI.d.ts +159 -0
- package/dist/validation.d.ts +138 -0
- package/dist/validation.js +477 -0
- package/dist/validation.js.map +1 -0
- package/docs/INDEX.md +192 -0
- package/docs/README.md +165 -0
- package/docs/api/.nojekyll +1 -0
- package/docs/api/README.md +301 -0
- package/docs/api/classes/ErrorBoundary.md +144 -0
- package/docs/api/classes/PublicErrorBoundary.md +132 -0
- package/docs/api/interfaces/AggregateConfig.md +43 -0
- package/docs/api/interfaces/ButtonProps.md +53 -0
- package/docs/api/interfaces/CardProps.md +40 -0
- package/docs/api/interfaces/ColorPalette.md +7 -0
- package/docs/api/interfaces/ColorShade.md +41 -0
- package/docs/api/interfaces/DataTableAction.md +200 -0
- package/docs/api/interfaces/DataTableColumn.md +300 -0
- package/docs/api/interfaces/DataTableProps.md +517 -0
- package/docs/api/interfaces/DataTableToolbarButton.md +96 -0
- package/docs/api/interfaces/EmptyStateConfig.md +61 -0
- package/docs/api/interfaces/EventContextType.md +96 -0
- package/docs/api/interfaces/EventLogoProps.md +152 -0
- package/docs/api/interfaces/EventProviderProps.md +19 -0
- package/docs/api/interfaces/FileSizeLimits.md +7 -0
- package/docs/api/interfaces/FileUploadProps.md +154 -0
- package/docs/api/interfaces/FooterProps.md +105 -0
- package/docs/api/interfaces/InactivityWarningModalProps.md +115 -0
- package/docs/api/interfaces/InputProps.md +53 -0
- package/docs/api/interfaces/LabelProps.md +107 -0
- package/docs/api/interfaces/LoginFormProps.md +184 -0
- package/docs/api/interfaces/NavigationItem.md +176 -0
- package/docs/api/interfaces/NavigationMenuProps.md +236 -0
- package/docs/api/interfaces/Organisation.md +140 -0
- package/docs/api/interfaces/OrganisationContextType.md +377 -0
- package/docs/api/interfaces/OrganisationMembership.md +140 -0
- package/docs/api/interfaces/OrganisationProviderProps.md +19 -0
- package/docs/api/interfaces/OrganisationSecurityError.md +62 -0
- package/docs/api/interfaces/PaceAppLayoutProps.md +393 -0
- package/docs/api/interfaces/PaceLoginPageProps.md +34 -0
- package/docs/api/interfaces/PaletteData.md +41 -0
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +94 -0
- package/docs/api/interfaces/PublicErrorBoundaryState.md +68 -0
- package/docs/api/interfaces/PublicLoadingSpinnerProps.md +86 -0
- package/docs/api/interfaces/PublicPageFooterProps.md +112 -0
- package/docs/api/interfaces/PublicPageHeaderProps.md +138 -0
- package/docs/api/interfaces/PublicPageLayoutProps.md +138 -0
- package/docs/api/interfaces/StorageConfig.md +41 -0
- package/docs/api/interfaces/StorageFileInfo.md +74 -0
- package/docs/api/interfaces/StorageFileMetadata.md +140 -0
- package/docs/api/interfaces/StorageListOptions.md +86 -0
- package/docs/api/interfaces/StorageListResult.md +41 -0
- package/docs/api/interfaces/StorageUploadOptions.md +88 -0
- package/docs/api/interfaces/StorageUploadResult.md +63 -0
- package/docs/api/interfaces/StorageUrlOptions.md +47 -0
- package/docs/api/interfaces/StyleImport.md +19 -0
- package/docs/api/interfaces/ToastActionElement.md +9 -0
- package/docs/api/interfaces/ToastProps.md +9 -0
- package/docs/api/interfaces/UnifiedAuthContextType.md +1108 -0
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +171 -0
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +136 -0
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +123 -0
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
- package/docs/api/interfaces/UsePublicEventOptions.md +34 -0
- package/docs/api/interfaces/UsePublicEventReturn.md +68 -0
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +94 -0
- package/docs/api/interfaces/UserEventAccess.md +118 -0
- package/docs/api/interfaces/UserMenuProps.md +86 -0
- package/docs/api/interfaces/UserProfile.md +63 -0
- package/docs/api/modules.md +4153 -0
- package/docs/api-reference/components.md +1623 -0
- package/docs/api-reference/hooks.md +627 -0
- package/docs/api-reference/providers.md +487 -0
- package/docs/api-reference/types.md +1005 -0
- package/docs/api-reference/utilities.md +1104 -0
- package/docs/app.css.example +53 -0
- package/docs/architecture/README.md +577 -0
- package/docs/best-practices/README.md +400 -0
- package/docs/best-practices/deployment.md +1042 -0
- package/docs/best-practices/performance.md +789 -0
- package/docs/best-practices/security.md +881 -0
- package/docs/best-practices/testing.md +981 -0
- package/docs/consuming-app-example.md +290 -0
- package/docs/consuming-app-vite-config.md +233 -0
- package/docs/core-concepts/authentication.md +98 -0
- package/docs/core-concepts/events.md +756 -0
- package/docs/core-concepts/organisations.md +790 -0
- package/docs/core-concepts/permissions.md +729 -0
- package/docs/core-concepts/rbac-system.md +233 -0
- package/docs/database-schema-requirements.md +172 -0
- package/docs/documentation-style-checklist.md +294 -0
- package/docs/examples/navigation-menu-auth-fix.md +344 -0
- package/docs/getting-started/examples/README.md +106 -0
- package/docs/getting-started/examples/basic-auth-app.md +521 -0
- package/docs/getting-started/examples/full-featured-app.md +616 -0
- package/docs/getting-started/installation.md +269 -0
- package/docs/getting-started/quick-start.md +401 -0
- package/docs/implementation-guides/app-layout.md +983 -0
- package/docs/implementation-guides/data-tables.md +1898 -0
- package/docs/implementation-guides/dynamic-colors.md +195 -0
- package/docs/implementation-guides/forms.md +578 -0
- package/docs/implementation-guides/hierarchical-datatable.md +850 -0
- package/docs/implementation-guides/large-datasets.md +281 -0
- package/docs/implementation-guides/navigation.md +844 -0
- package/docs/implementation-guides/performance.md +403 -0
- package/docs/implementation-guides/permission-enforcement.md +764 -0
- package/docs/implementation-guides/public-pages.md +752 -0
- package/docs/migration/README.md +493 -0
- package/docs/migration/organisation-context-timing-fix.md +217 -0
- package/docs/migration/quick-migration-guide.md +320 -0
- package/docs/migration/rbac-migration.md +571 -0
- package/docs/migration/v0.4.15-tailwind-scanning.md +272 -0
- package/docs/migration/v0.4.16-css-first-approach.md +306 -0
- package/docs/migration/v0.4.17-source-path-fix.md +229 -0
- package/docs/migration-guide.md +168 -0
- package/docs/performance/README.md +551 -0
- package/docs/print-components/README.md +258 -0
- package/docs/print-components/api-reference.md +636 -0
- package/docs/print-components/examples/README.md +204 -0
- package/docs/print-components/examples/basic-report.tsx +92 -0
- package/docs/print-components/examples/card-catalog.tsx +149 -0
- package/docs/print-components/examples/cover-page-report.tsx +163 -0
- package/docs/print-components/quick-start.md +363 -0
- package/docs/quick-reference.md +576 -0
- package/docs/rbac/README.md +265 -0
- package/docs/rbac/advanced-patterns.md +776 -0
- package/docs/rbac/api-reference.md +1033 -0
- package/docs/rbac/examples.md +883 -0
- package/docs/rbac/getting-started.md +679 -0
- package/docs/rbac/quick-start.md +619 -0
- package/docs/rbac/super-admin-guide.md +592 -0
- package/docs/rbac/troubleshooting.md +316 -0
- package/docs/security/README.md +680 -0
- package/docs/security/checklist.md +343 -0
- package/docs/style-guide.md +522 -0
- package/docs/styles/README.md +319 -0
- package/docs/testing/README.md +874 -0
- package/docs/troubleshooting/README.md +497 -0
- package/docs/troubleshooting/common-issues.md +1563 -0
- package/docs/troubleshooting/database-view-compatibility.md +119 -0
- package/docs/troubleshooting/debugging.md +1117 -0
- package/docs/troubleshooting/migration.md +918 -0
- package/docs/troubleshooting/organisation-context-setup.md +277 -0
- package/docs/troubleshooting/react-hooks-issue-analysis.md +166 -0
- package/docs/troubleshooting/styling-issues.md +219 -0
- package/docs/troubleshooting/tailwind-content-scanning.md +213 -0
- package/docs/usage.md +175 -0
- package/docs/visual-testing.md +114 -0
- package/package.json +211 -0
- package/src/__mocks__/lucide-react.ts +181 -0
- package/src/__tests__/README.md +404 -0
- package/src/__tests__/debug-provider.unit.test.tsx +67 -0
- package/src/__tests__/e2e/workflows.test.tsx +373 -0
- package/src/__tests__/hybridPermissions.unit.test.tsx +474 -0
- package/src/__tests__/index.integration.test.ts +491 -0
- package/src/__tests__/mocks/MockAuthProvider-standalone.tsx +47 -0
- package/src/__tests__/mocks/MockAuthProvider.tsx +63 -0
- package/src/__tests__/mocks/enhancedSupabaseMock.ts +252 -0
- package/src/__tests__/mocks/index.test.ts +23 -0
- package/src/__tests__/mocks/index.ts +16 -0
- package/src/__tests__/mocks/mockAuth.ts +155 -0
- package/src/__tests__/mocks/mockSupabase.ts +83 -0
- package/src/__tests__/mocks/mockSupabaseClient.ts +63 -0
- package/src/__tests__/mocks/providers.tsx +22 -0
- package/src/__tests__/patterns/__tests__/testPatterns.test.ts +394 -0
- package/src/__tests__/patterns/testPatterns.ts +124 -0
- package/src/__tests__/performance/componentPerformance.performance.test.ts +27 -0
- package/src/__tests__/performance/index.ts +24 -0
- package/src/__tests__/performance/performanceValidation.performance.test.ts +15 -0
- package/src/__tests__/security/security.unit.test.tsx +7 -0
- package/src/__tests__/security/securityValidation.security.test.tsx +153 -0
- package/src/__tests__/setup.ts +259 -0
- package/src/__tests__/setupTests.d.ts +1 -0
- package/src/__tests__/shared/componentTestUtils.tsx +475 -0
- package/src/__tests__/shared/errorHandlingTestUtils.ts +107 -0
- package/src/__tests__/shared/index.ts +81 -0
- package/src/__tests__/shared/integrationTestUtils.tsx +375 -0
- package/src/__tests__/shared/performanceTestUtils.tsx +476 -0
- package/src/__tests__/shared/testUtils.optimized.tsx +627 -0
- package/src/__tests__/simple.test.tsx +20 -0
- package/src/__tests__/templates/accessibility.test.template.tsx +279 -0
- package/src/__tests__/templates/component.test.template.tsx +122 -0
- package/src/__tests__/templates/integration.test.template.tsx +199 -0
- package/src/__tests__/test-utils/dataFactories.ts +60 -0
- package/src/__tests__/test-utils/index.ts +6 -0
- package/src/__tests__/typeSafety.unit.test.ts +65 -0
- package/src/__tests__/unifiedAuth.unit.test.tsx +151 -0
- package/src/__tests__/utils/accessibilityHelpers.ts +254 -0
- package/src/__tests__/utils/assertions.ts +50 -0
- package/src/__tests__/utils/deterministicHelpers.ts +31 -0
- package/src/__tests__/utils/edgeCaseConfig.test.ts +75 -0
- package/src/__tests__/utils/edgeCaseConfig.ts +98 -0
- package/src/__tests__/utils/mockHelpers.ts +149 -0
- package/src/__tests__/utils/mockLoader.ts +101 -0
- package/src/__tests__/utils/performanceHelpers.ts +55 -0
- package/src/__tests__/utils/performanceTestHelpers.ts +68 -0
- package/src/__tests__/utils/testDataFactories.ts +28 -0
- package/src/__tests__/utils/testIsolation.ts +67 -0
- package/src/__tests__/utils/visualTestHelpers.ts +20 -0
- package/src/__tests__/visual/__snapshots__/componentSnapshots.visual.test.tsx.snap +68 -0
- package/src/__tests__/visual/__snapshots__/componentVisuals.visual.test.tsx.snap +14 -0
- package/src/__tests__/visual/__snapshots__/visualRegression.test.tsx.snap +217 -0
- package/src/__tests__/visual/__snapshots__/visualRegression.visual.test.tsx.snap +24 -0
- package/src/__tests__/visual/componentSnapshots.visual.test.tsx +33 -0
- package/src/__tests__/visual/componentVisuals.visual.test.tsx +12 -0
- package/src/__tests__/visual/visualRegression.visual.test.tsx +20 -0
- package/src/components/Alert/Alert.tsx +134 -0
- package/src/components/Alert/__tests__/Alert.unit.test.tsx +381 -0
- package/src/components/Alert/index.ts +2 -0
- package/src/components/Avatar/Avatar.tsx +84 -0
- package/src/components/Avatar/__tests__/Avatar.unit.test.tsx +232 -0
- package/src/components/Avatar/index.ts +2 -0
- package/src/components/Button/Button.tsx +270 -0
- package/src/components/Button/__tests__/Button.accessibility.test.tsx +131 -0
- package/src/components/Button/__tests__/Button.comprehensive.test.tsx +721 -0
- package/src/components/Button/__tests__/Button.unit.test.tsx +189 -0
- package/src/components/Button/__tests__/EventSelector.integration.test.tsx +285 -0
- package/src/components/Button/index.ts +2 -0
- package/src/components/Card/Card.tsx +271 -0
- package/src/components/Card/__tests__/Card.accessibility.test.tsx +394 -0
- package/src/components/Card/__tests__/Card.comprehensive.test.tsx +599 -0
- package/src/components/Card/__tests__/Card.integration.test.tsx +673 -0
- package/src/components/Card/__tests__/Card.performance.test.tsx +546 -0
- package/src/components/Card/__tests__/Card.unit.test.tsx +330 -0
- package/src/components/Card/__tests__/Card.visual.test.tsx +599 -0
- package/src/components/Card/__tests__/README.md +211 -0
- package/src/components/Card/index.ts +1 -0
- package/src/components/Checkbox/Checkbox.tsx +75 -0
- package/src/components/Checkbox/__mocks__/Checkbox.tsx +2 -0
- package/src/components/Checkbox/__tests__/Checkbox.unit.test.tsx +520 -0
- package/src/components/Checkbox/index.ts +2 -0
- package/src/components/DataTable/DataTable.tsx +440 -0
- package/src/components/DataTable/__tests__/DataTable.autoSizing.test.tsx +526 -0
- package/src/components/DataTable/__tests__/DataTable.errorHandling.test.tsx +259 -0
- package/src/components/DataTable/__tests__/DataTable.hierarchical.test.tsx +675 -0
- package/src/components/DataTable/__tests__/DataTable.infinite-loop.test.tsx +324 -0
- package/src/components/DataTable/__tests__/DataTable.integration.test.tsx +724 -0
- package/src/components/DataTable/__tests__/DataTable.performance.test.tsx +597 -0
- package/src/components/DataTable/__tests__/DataTable.permissions.test.tsx +306 -0
- package/src/components/DataTable/__tests__/DataTable.regressionFixes.test.tsx +546 -0
- package/src/components/DataTable/__tests__/DataTable.selection.controlled.test.tsx +386 -0
- package/src/components/DataTable/__tests__/DataTable.selection.test.tsx +338 -0
- package/src/components/DataTable/__tests__/DataTable.userWorkflows.test.tsx +310 -0
- package/src/components/DataTable/__tests__/DataTable.workflowValidation.test.tsx +489 -0
- package/src/components/DataTable/__tests__/DataTable.workflows.test.tsx +701 -0
- package/src/components/DataTable/__tests__/README.md +136 -0
- package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +66 -0
- package/src/components/DataTable/__tests__/performance-regression.test.tsx +788 -0
- package/src/components/DataTable/__tests__/performance.test.tsx +365 -0
- package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +103 -0
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +382 -0
- package/src/components/DataTable/__tests__/test-utils.ts +94 -0
- package/src/components/DataTable/components/ActionButtons.tsx +177 -0
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +160 -0
- package/src/components/DataTable/components/ColumnFilter.tsx +114 -0
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +100 -0
- package/src/components/DataTable/components/DataTableBody.tsx +462 -0
- package/src/components/DataTable/components/DataTableCore.tsx +869 -0
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +214 -0
- package/src/components/DataTable/components/DataTableHeader.tsx +31 -0
- package/src/components/DataTable/components/DataTableModals.tsx +87 -0
- package/src/components/DataTable/components/DataTableToolbar.tsx +251 -0
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +148 -0
- package/src/components/DataTable/components/EditableRow.tsx +160 -0
- package/src/components/DataTable/components/EmptyState.tsx +64 -0
- package/src/components/DataTable/components/ExpandButton.tsx +113 -0
- package/src/components/DataTable/components/FilterRow.tsx +101 -0
- package/src/components/DataTable/components/GroupHeader.tsx +42 -0
- package/src/components/DataTable/components/GroupingDropdown.tsx +96 -0
- package/src/components/DataTable/components/ImportModal.tsx +345 -0
- package/src/components/DataTable/components/LoadingState.tsx +12 -0
- package/src/components/DataTable/components/PaginationControls.tsx +332 -0
- package/src/components/DataTable/components/UnifiedTableBody.tsx +911 -0
- package/src/components/DataTable/components/ViewRowModal.tsx +68 -0
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +593 -0
- package/src/components/DataTable/components/__tests__/ActionButtons.unit.test.tsx +150 -0
- package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +224 -0
- package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.unit.test.tsx +244 -0
- package/src/components/DataTable/components/__tests__/DataTable.accessibility.test.tsx +523 -0
- package/src/components/DataTable/components/__tests__/DataTable.integration.test.tsx +401 -0
- package/src/components/DataTable/components/__tests__/DataTable.performance.test.tsx +161 -0
- package/src/components/DataTable/components/__tests__/DataTable.real.test.tsx +251 -0
- package/src/components/DataTable/components/__tests__/DataTable.security.test.tsx +172 -0
- package/src/components/DataTable/components/__tests__/DataTable.unit.test.tsx +290 -0
- package/src/components/DataTable/components/__tests__/DataTableBody.unit.test.tsx +147 -0
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.unit.test.tsx +182 -0
- package/src/components/DataTable/components/__tests__/DataTableHeader.unit.test.tsx +143 -0
- package/src/components/DataTable/components/__tests__/DataTableModals.unit.test.tsx +123 -0
- package/src/components/DataTable/components/__tests__/EditableRow.unit.test.tsx +660 -0
- package/src/components/DataTable/components/__tests__/EmptyState.unit.test.tsx +256 -0
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +498 -0
- package/src/components/DataTable/components/__tests__/FilterRow.unit.test.tsx +112 -0
- package/src/components/DataTable/components/__tests__/FilteringToggle.unit.test.tsx +130 -0
- package/src/components/DataTable/components/__tests__/GroupHeader.unit.test.tsx +172 -0
- package/src/components/DataTable/components/__tests__/GroupingDropdown.unit.test.tsx +222 -0
- package/src/components/DataTable/components/__tests__/ImportModal.unit.test.tsx +780 -0
- package/src/components/DataTable/components/__tests__/LoadingState.unit.test.tsx +65 -0
- package/src/components/DataTable/components/__tests__/PaginationControls.unit.test.tsx +634 -0
- package/src/components/DataTable/components/__tests__/StateComponents.unit.test.tsx +48 -0
- package/src/components/DataTable/components/__tests__/UnifiedTableBody.hierarchical.test.tsx +541 -0
- package/src/components/DataTable/components/__tests__/ViewRowModal.unit.test.tsx +228 -0
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.unit.test.tsx +568 -0
- package/src/components/DataTable/components/index.ts +17 -0
- package/src/components/DataTable/context/DataTableContext.tsx +97 -0
- package/src/components/DataTable/core/ActionManager.ts +235 -0
- package/src/components/DataTable/core/ColumnFactory.ts +268 -0
- package/src/components/DataTable/core/ColumnManager.ts +205 -0
- package/src/components/DataTable/core/DataManager.ts +188 -0
- package/src/components/DataTable/core/DataTableContext.tsx +182 -0
- package/src/components/DataTable/core/LocalDataAdapter.ts +264 -0
- package/src/components/DataTable/core/PluginRegistry.ts +229 -0
- package/src/components/DataTable/core/StateManager.ts +311 -0
- package/src/components/DataTable/core/__tests__/ActionManager.unit.test.ts +405 -0
- package/src/components/DataTable/core/__tests__/ArchitectureIntegration.unit.test.tsx +445 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.unit.test.ts +288 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.unit.test.ts +623 -0
- package/src/components/DataTable/core/__tests__/DataManager.unit.test.ts +431 -0
- package/src/components/DataTable/core/__tests__/DataTableContext.unit.test.tsx +433 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.unit.test.ts +422 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.unit.test.tsx +207 -0
- package/src/components/DataTable/core/__tests__/StateManager.unit.test.ts +278 -0
- package/src/components/DataTable/core/index.ts +8 -0
- package/src/components/DataTable/core/interfaces.ts +338 -0
- package/src/components/DataTable/examples/AutoSizingExample.tsx +180 -0
- package/src/components/DataTable/examples/ColumnSizingComparison.tsx +235 -0
- package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +418 -0
- package/src/components/DataTable/examples/HierarchicalExample.tsx +472 -0
- package/src/components/DataTable/examples/InitialPageSizeExample.tsx +173 -0
- package/src/components/DataTable/examples/PerformanceExample.tsx +502 -0
- package/src/components/DataTable/examples/__tests__/PerformanceExample.unit.test.tsx +281 -0
- package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.unit.test.ts +407 -0
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.unit.test.ts +679 -0
- package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +95 -0
- package/src/components/DataTable/hooks/useColumnReordering.ts +110 -0
- package/src/components/DataTable/hooks/useDataTableState.ts +325 -0
- package/src/components/DataTable/hooks/useHierarchicalState.ts +174 -0
- package/src/components/DataTable/index.ts +70 -0
- package/src/components/DataTable/styles.ts +171 -0
- package/src/components/DataTable/types.ts +475 -0
- package/src/components/DataTable/utils/__tests__/columnSizing.test.ts +237 -0
- package/src/components/DataTable/utils/__tests__/debugTools.unit.test.ts +267 -0
- package/src/components/DataTable/utils/__tests__/errorHandling.unit.test.ts +467 -0
- package/src/components/DataTable/utils/__tests__/exportUtils.unit.test.ts +380 -0
- package/src/components/DataTable/utils/__tests__/flexibleImport.unit.test.ts +233 -0
- package/src/components/DataTable/utils/__tests__/performanceUtils.unit.test.ts +414 -0
- package/src/components/DataTable/utils/columnSizing.ts +125 -0
- package/src/components/DataTable/utils/debugTools.ts +583 -0
- package/src/components/DataTable/utils/errorHandling.ts +494 -0
- package/src/components/DataTable/utils/exportUtils.ts +126 -0
- package/src/components/DataTable/utils/flexibleImport.ts +510 -0
- package/src/components/DataTable/utils/hierarchicalSorting.ts +151 -0
- package/src/components/DataTable/utils/hierarchicalUtils.ts +218 -0
- package/src/components/DataTable/utils/index.ts +1 -0
- package/src/components/DataTable/utils/performanceUtils.ts +351 -0
- package/src/components/Dialog/Dialog.tsx +782 -0
- package/src/components/Dialog/README.md +804 -0
- package/src/components/Dialog/__tests__/Dialog.accessibility.test.tsx +521 -0
- package/src/components/Dialog/__tests__/Dialog.auto-size.example.tsx +157 -0
- package/src/components/Dialog/__tests__/Dialog.enhanced.test.tsx +538 -0
- package/src/components/Dialog/__tests__/Dialog.unit.test.tsx +1373 -0
- package/src/components/Dialog/examples/BasicHtmlTest.tsx +55 -0
- package/src/components/Dialog/examples/DebugHtmlExample.tsx +68 -0
- package/src/components/Dialog/examples/HtmlDialogExample.tsx +202 -0
- package/src/components/Dialog/examples/SimpleHtmlTest.tsx +61 -0
- package/src/components/Dialog/examples/SmartDialogExample.tsx +322 -0
- package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +151 -0
- package/src/components/Dialog/index.ts +12 -0
- package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
- package/src/components/Dialog/utils/safeHtml.ts +185 -0
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +312 -0
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.accessibility.test.tsx +517 -0
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.integration.test.tsx +572 -0
- package/src/components/ErrorBoundary/__tests__/ErrorBoundary.unit.test.tsx +579 -0
- package/src/components/ErrorBoundary/index.ts +8 -0
- package/src/components/EventSelector/EventSelector.tsx +360 -0
- package/src/components/EventSelector/__tests__/EventSelector.test.tsx +528 -0
- package/src/components/EventSelector/index.ts +3 -0
- package/src/components/EventSelector/types.ts +79 -0
- package/src/components/FileUpload/FileUpload.example.tsx +218 -0
- package/src/components/FileUpload/FileUpload.tsx +237 -0
- package/src/components/FileUpload/__tests__/FileUpload.integration.test.tsx +992 -0
- package/src/components/FileUpload/__tests__/FileUpload.real.test.tsx +927 -0
- package/src/components/FileUpload/__tests__/FileUpload.test.tsx +855 -0
- package/src/components/FileUpload/__tests__/FileUpload.unit.test.tsx +1311 -0
- package/src/components/FileUpload/__tests__/FileUpload.unmocked.test.tsx +937 -0
- package/src/components/FileUpload/index.ts +6 -0
- package/src/components/Footer/Footer.tsx +197 -0
- package/src/components/Footer/__tests__/Footer.accessibility.test.tsx +359 -0
- package/src/components/Footer/__tests__/Footer.integration.test.tsx +353 -0
- package/src/components/Footer/__tests__/Footer.performance.test.tsx +309 -0
- package/src/components/Footer/__tests__/Footer.unit.test.tsx +309 -0
- package/src/components/Footer/__tests__/Footer.visual.test.tsx +335 -0
- package/src/components/Footer/index.ts +17 -0
- package/src/components/Form/Form.tsx +166 -0
- package/src/components/Form/FormErrorSummary.tsx +113 -0
- package/src/components/Form/FormField.tsx +249 -0
- package/src/components/Form/FormFieldset.tsx +127 -0
- package/src/components/Form/FormLiveRegion.tsx +198 -0
- package/src/components/Form/__tests__/Form.accessibility.test.tsx +820 -0
- package/src/components/Form/__tests__/Form.unit.test.tsx +305 -0
- package/src/components/Form/__tests__/FormErrorSummary.unit.test.tsx +285 -0
- package/src/components/Form/__tests__/FormFieldset.unit.test.tsx +241 -0
- package/src/components/Form/index.ts +26 -0
- package/src/components/Header/Header.tsx +301 -0
- package/src/components/Header/__tests__/Header.accessibility.test.tsx +382 -0
- package/src/components/Header/__tests__/Header.comprehensive.test.tsx +509 -0
- package/src/components/Header/__tests__/Header.unit.test.tsx +335 -0
- package/src/components/Header/index.ts +4 -0
- package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +196 -0
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +164 -0
- package/src/components/InactivityWarningModal/__tests__/InactivityWarningModal.unit.test.tsx +224 -0
- package/src/components/InactivityWarningModal/index.ts +9 -0
- package/src/components/Input/Input.tsx +201 -0
- package/src/components/Input/__mocks__/Input.tsx +2 -0
- package/src/components/Input/__tests__/Input.accessibility.test.tsx +632 -0
- package/src/components/Input/__tests__/Input.unit.test.tsx +1121 -0
- package/src/components/Input/index.ts +9 -0
- package/src/components/Label/Label.tsx +186 -0
- package/src/components/Label/__tests__/Label.accessibility.test.tsx +239 -0
- package/src/components/Label/__tests__/Label.unit.test.tsx +331 -0
- package/src/components/Label/index.ts +2 -0
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +98 -0
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.accessibility.test.tsx +116 -0
- package/src/components/LoadingSpinner/__tests__/LoadingSpinner.unit.test.tsx +144 -0
- package/src/components/LoadingSpinner/index.ts +3 -0
- package/src/components/LoginForm/LoginForm.tsx +273 -0
- package/src/components/LoginForm/__tests__/LoginForm.accessibility.test.tsx +201 -0
- package/src/components/LoginForm/__tests__/LoginForm.unit.test.tsx +119 -0
- package/src/components/LoginForm/index.ts +3 -0
- package/src/components/NavigationMenu/NavigationMenu.tsx +698 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.accessibility.test.tsx +378 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.enhanced.test.tsx +768 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.integration.test.tsx +576 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.performance.test.tsx +585 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.real.component.test.tsx +783 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.enhanced.test.tsx +810 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.security.test.tsx +494 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.unit.test.tsx +331 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.userWorkflows.test.tsx +347 -0
- package/src/components/NavigationMenu/__tests__/NavigationMenu.workflows.test.tsx +584 -0
- package/src/components/NavigationMenu/index.ts +10 -0
- package/src/components/NavigationMenu/types.ts +85 -0
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +304 -0
- package/src/components/OrganisationSelector/__tests__/OrganisationSelector.unit.test.tsx +664 -0
- package/src/components/OrganisationSelector/index.ts +9 -0
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +699 -0
- package/src/components/PaceAppLayout/README.md +278 -0
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +288 -0
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +889 -0
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +629 -0
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +782 -0
- package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +904 -0
- package/src/components/PaceAppLayout/index.ts +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +221 -0
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.accessibility.test.tsx +463 -0
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.integration.test.tsx +586 -0
- package/src/components/PaceLoginPage/__tests__/PaceLoginPage.unit.test.tsx +533 -0
- package/src/components/PaceLoginPage/index.ts +1 -0
- package/src/components/PasswordReset/PasswordChangeForm.tsx +186 -0
- package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.accessibility.test.tsx +408 -0
- package/src/components/PasswordReset/__tests__/PasswordChangeForm.unit.test.tsx +561 -0
- package/src/components/PasswordReset/__tests__/PasswordReset.integration.test.tsx +304 -0
- package/src/components/PasswordReset/__tests__/PasswordResetForm.accessibility.test.tsx +20 -0
- package/src/components/PasswordReset/__tests__/PasswordResetForm.unit.test.tsx +523 -0
- package/src/components/PasswordReset/__tests__/__mocks__/UnifiedAuthProvider.ts +29 -0
- package/src/components/PasswordReset/index.ts +4 -0
- package/src/components/Print/__tests__/Print.comprehensive.test.tsx +331 -0
- package/src/components/PrintButton/PrintButton.tsx +321 -0
- package/src/components/PrintButton/PrintButtonGroup.tsx +84 -0
- package/src/components/PrintButton/PrintToolbar.tsx +94 -0
- package/src/components/PrintButton/__tests__/PrintButton.unit.test.tsx +429 -0
- package/src/components/PrintButton/__tests__/PrintButtonGroup.unit.test.tsx +277 -0
- package/src/components/PrintButton/__tests__/PrintToolbar.unit.test.tsx +264 -0
- package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +438 -0
- package/src/components/PrintButton/index.ts +33 -0
- package/src/components/PrintButton/types.ts +173 -0
- package/src/components/PrintCard/PrintCard.tsx +154 -0
- package/src/components/PrintCard/PrintCardContent.tsx +57 -0
- package/src/components/PrintCard/PrintCardFooter.tsx +60 -0
- package/src/components/PrintCard/PrintCardGrid.tsx +91 -0
- package/src/components/PrintCard/PrintCardHeader.tsx +78 -0
- package/src/components/PrintCard/PrintCardImage.tsx +81 -0
- package/src/components/PrintCard/__tests__/PrintCard.unit.test.tsx +233 -0
- package/src/components/PrintCard/__tests__/PrintCardContent.test.tsx +284 -0
- package/src/components/PrintCard/__tests__/PrintCardGrid.unit.test.tsx +214 -0
- package/src/components/PrintCard/__tests__/PrintCardImage.unit.test.tsx +264 -0
- package/src/components/PrintCard/examples/PrintCardShowcase.tsx +239 -0
- package/src/components/PrintCard/index.ts +34 -0
- package/src/components/PrintCard/types.ts +171 -0
- package/src/components/PrintDataTable/PrintDataTable.tsx +215 -0
- package/src/components/PrintDataTable/PrintTableGroup.tsx +90 -0
- package/src/components/PrintDataTable/PrintTableRow.tsx +76 -0
- package/src/components/PrintDataTable/__tests__/PrintDataTable.unit.test.tsx +361 -0
- package/src/components/PrintDataTable/__tests__/PrintTableGroup.unit.test.tsx +314 -0
- package/src/components/PrintDataTable/__tests__/PrintTableRow.unit.test.tsx +362 -0
- package/src/components/PrintDataTable/index.ts +25 -0
- package/src/components/PrintDataTable/types.ts +67 -0
- package/src/components/PrintFooter/PrintFooter.tsx +183 -0
- package/src/components/PrintFooter/PrintFooterContent.tsx +71 -0
- package/src/components/PrintFooter/PrintFooterInfo.tsx +86 -0
- package/src/components/PrintFooter/PrintPageNumber.tsx +90 -0
- package/src/components/PrintFooter/__tests__/PrintFooter.unit.test.tsx +500 -0
- package/src/components/PrintFooter/__tests__/PrintFooterContent.unit.test.tsx +321 -0
- package/src/components/PrintFooter/__tests__/PrintFooterInfo.unit.test.tsx +335 -0
- package/src/components/PrintFooter/__tests__/PrintPageNumber.unit.test.tsx +340 -0
- package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +390 -0
- package/src/components/PrintFooter/index.ts +30 -0
- package/src/components/PrintFooter/types.ts +149 -0
- package/src/components/PrintGrid/PrintGrid.tsx +180 -0
- package/src/components/PrintGrid/PrintGridBreakpoint.tsx +109 -0
- package/src/components/PrintGrid/PrintGridContainer.tsx +128 -0
- package/src/components/PrintGrid/PrintGridItem.tsx +220 -0
- package/src/components/PrintGrid/__tests__/PrintGrid.unit.test.tsx +340 -0
- package/src/components/PrintGrid/__tests__/PrintGridBreakpoint.unit.test.tsx +261 -0
- package/src/components/PrintGrid/__tests__/PrintGridContainer.unit.test.tsx +338 -0
- package/src/components/PrintGrid/__tests__/PrintGridItem.unit.test.tsx +338 -0
- package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +359 -0
- package/src/components/PrintGrid/index.ts +31 -0
- package/src/components/PrintGrid/types.ts +159 -0
- package/src/components/PrintHeader/PrintCoverHeader.tsx +230 -0
- package/src/components/PrintHeader/PrintHeader.tsx +150 -0
- package/src/components/PrintHeader/__tests__/PrintCoverHeader.unit.test.tsx +309 -0
- package/src/components/PrintHeader/__tests__/PrintHeader.unit.test.tsx +202 -0
- package/src/components/PrintHeader/index.ts +17 -0
- package/src/components/PrintHeader/types.ts +42 -0
- package/src/components/PrintLayout/PrintLayout.tsx +122 -0
- package/src/components/PrintLayout/PrintLayoutContext.tsx +66 -0
- package/src/components/PrintLayout/PrintPageBreak.tsx +52 -0
- package/src/components/PrintLayout/__tests__/PrintLayout.unit.test.tsx +238 -0
- package/src/components/PrintLayout/examples/PrintShowcase.tsx +230 -0
- package/src/components/PrintLayout/index.ts +19 -0
- package/src/components/PrintLayout/types.ts +37 -0
- package/src/components/PrintPageBreak/PrintPageBreak.tsx +120 -0
- package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +90 -0
- package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +112 -0
- package/src/components/PrintPageBreak/__tests__/PrintPageBreak.unit.test.tsx +263 -0
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakGroup.unit.test.tsx +239 -0
- package/src/components/PrintPageBreak/__tests__/PrintPageBreakIndicator.unit.test.tsx +235 -0
- package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +279 -0
- package/src/components/PrintPageBreak/index.ts +23 -0
- package/src/components/PrintPageBreak/types.ts +94 -0
- package/src/components/PrintSection/PrintColumn.tsx +104 -0
- package/src/components/PrintSection/PrintDivider.tsx +101 -0
- package/src/components/PrintSection/PrintSection.tsx +129 -0
- package/src/components/PrintSection/PrintSectionContent.tsx +75 -0
- package/src/components/PrintSection/PrintSectionHeader.tsx +97 -0
- package/src/components/PrintSection/__tests__/PrintColumn.unit.test.tsx +385 -0
- package/src/components/PrintSection/__tests__/PrintDivider.unit.test.tsx +373 -0
- package/src/components/PrintSection/__tests__/PrintSection.unit.test.tsx +390 -0
- package/src/components/PrintSection/__tests__/PrintSectionContent.unit.test.tsx +321 -0
- package/src/components/PrintSection/__tests__/PrintSectionHeader.unit.test.tsx +334 -0
- package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +258 -0
- package/src/components/PrintSection/index.ts +33 -0
- package/src/components/PrintSection/types.ts +155 -0
- package/src/components/PrintText/PrintText.tsx +116 -0
- package/src/components/PrintText/__tests__/PrintText.unit.test.tsx +351 -0
- package/src/components/PrintText/index.ts +16 -0
- package/src/components/PrintText/types.ts +24 -0
- package/src/components/Progress/Progress.tsx +116 -0
- package/src/components/Progress/__tests__/Progress.accessibility.test.tsx +240 -0
- package/src/components/Progress/__tests__/Progress.unit.test.tsx +242 -0
- package/src/components/Progress/index.ts +3 -0
- package/src/components/PublicLayout/EventLogo.tsx +287 -0
- package/src/components/PublicLayout/PublicErrorBoundary.tsx +279 -0
- package/src/components/PublicLayout/PublicLoadingSpinner.tsx +208 -0
- package/src/components/PublicLayout/PublicPageContextChecker.tsx +130 -0
- package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
- package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
- package/src/components/PublicLayout/PublicPageFooter.tsx +124 -0
- package/src/components/PublicLayout/PublicPageHeader.tsx +178 -0
- package/src/components/PublicLayout/PublicPageLayout.tsx +232 -0
- package/src/components/PublicLayout/PublicPageProvider.tsx +137 -0
- package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +761 -0
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.simplified.test.tsx +228 -0
- package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +228 -0
- package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +459 -0
- package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +362 -0
- package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +522 -0
- package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +599 -0
- package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +513 -0
- package/src/components/PublicLayout/index.ts +51 -0
- package/src/components/RBAC/PagePermissionGuard.tsx +274 -0
- package/src/components/RBAC/RBACGuard.tsx +143 -0
- package/src/components/RBAC/RBACProvider.tsx +186 -0
- package/src/components/RBAC/RoleBasedContent.tsx +129 -0
- package/src/components/RBAC/__tests__/PagePermissionGuard.unit.test.tsx +674 -0
- package/src/components/RBAC/__tests__/RBAC.integration.test.tsx +573 -0
- package/src/components/RBAC/__tests__/RBACGuard.unit.test.tsx +467 -0
- package/src/components/RBAC/__tests__/RBACProvider.accessibility.test.tsx +475 -0
- package/src/components/RBAC/__tests__/RBACProvider.advanced.test.tsx +569 -0
- package/src/components/RBAC/__tests__/RBACProvider.integration.test.tsx +352 -0
- package/src/components/RBAC/__tests__/RBACProvider.unit.test.tsx +128 -0
- package/src/components/RBAC/__tests__/RoleBasedContent.unit.test.tsx +657 -0
- package/src/components/RBAC/index.ts +23 -0
- package/src/components/Select/Select.tsx +654 -0
- package/src/components/Select/__tests__/SearchableSelect.unit.test.tsx +437 -0
- package/src/components/Select/__tests__/Select.accessibility.test.tsx +1202 -0
- package/src/components/Select/__tests__/Select.actual.test.tsx +774 -0
- package/src/components/Select/__tests__/Select.comprehensive.test.tsx +837 -0
- package/src/components/Select/__tests__/Select.enhanced.test.tsx +1101 -0
- package/src/components/Select/__tests__/Select.integration.test.tsx +772 -0
- package/src/components/Select/__tests__/Select.performance.test.tsx +695 -0
- package/src/components/Select/__tests__/Select.real-world.test.tsx +1046 -0
- package/src/components/Select/__tests__/Select.search-algorithms.test.tsx +968 -0
- package/src/components/Select/__tests__/Select.unit.test.tsx +647 -0
- package/src/components/Select/__tests__/Select.utils.test.tsx +890 -0
- package/src/components/Select/index.ts +1 -0
- package/src/components/SuperAdminGuard.tsx +116 -0
- package/src/components/Table/Table.tsx +222 -0
- package/src/components/Table/__tests__/Table.accessibility.test.tsx +233 -0
- package/src/components/Table/__tests__/Table.unit.test.tsx +235 -0
- package/src/components/Table/index.ts +11 -0
- package/src/components/Toast/Toast.tsx +339 -0
- package/src/components/Toast/__tests__/Toast.accessibility.test.tsx +238 -0
- package/src/components/Toast/__tests__/Toast.integration.test.tsx +699 -0
- package/src/components/Toast/__tests__/Toast.unit.test.tsx +750 -0
- package/src/components/Toast/index.ts +14 -0
- package/src/components/Tooltip/Tooltip.tsx +167 -0
- package/src/components/Tooltip/__tests__/Tooltip.accessibility.test.tsx +121 -0
- package/src/components/Tooltip/__tests__/Tooltip.unit.test.tsx +185 -0
- package/src/components/Tooltip/index.ts +7 -0
- package/src/components/UserMenu/UserMenu.tsx +243 -0
- package/src/components/UserMenu/__tests__/UserMenu.accessibility.test.tsx +139 -0
- package/src/components/UserMenu/__tests__/UserMenu.integration.test.tsx +188 -0
- package/src/components/UserMenu/__tests__/UserMenu.unit.test.tsx +458 -0
- package/src/components/UserMenu/index.ts +3 -0
- package/src/components/__tests__/EdgeCaseTesting.enhanced.test.tsx +523 -0
- package/src/components/__tests__/ErrorTesting.enhanced.test.tsx +455 -0
- package/src/components/__tests__/SuperAdminGuard.test.tsx +456 -0
- package/src/components/__tests__/SuperAdminGuard.unit.test.tsx +456 -0
- package/src/components/examples/PermissionExample.tsx +150 -0
- package/src/components/examples/__tests__/PermissionExample.unit.test.tsx +360 -0
- package/src/components/index.ts +434 -0
- package/src/components.ts +19 -0
- package/src/constants/performance.ts +14 -0
- package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
- package/src/examples/PublicEventPage.tsx +274 -0
- package/src/examples/PublicPageApp.tsx +308 -0
- package/src/examples/PublicPageUsageExample.tsx +216 -0
- package/src/fonts/georama-italic.woff2 +0 -0
- package/src/fonts/georama.woff2 +0 -0
- package/src/fonts/open-sans-italic.woff2 +0 -0
- package/src/fonts/open-sans.woff2 +0 -0
- package/src/fonts/reddit-mono.woff2 +0 -0
- package/src/hooks/__tests__/hooks.integration.test.tsx +575 -0
- package/src/hooks/__tests__/useApiFetch.unit.test.ts +115 -0
- package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +133 -0
- package/src/hooks/__tests__/useDebounce.unit.test.ts +82 -0
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +293 -0
- package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +385 -0
- package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +286 -0
- package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +838 -0
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +627 -0
- package/src/hooks/__tests__/useRBAC.unit.test.ts +903 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +537 -0
- package/src/hooks/__tests__/useToast.unit.test.tsx +62 -0
- package/src/hooks/__tests__/useZodForm.unit.test.tsx +37 -0
- package/src/hooks/index.ts +56 -0
- package/src/hooks/public/__tests__/usePublicEvent.test.tsx +397 -0
- package/src/hooks/public/__tests__/usePublicEventLogo.test.tsx +690 -0
- package/src/hooks/public/__tests__/usePublicRouteParams.test.tsx +449 -0
- package/src/hooks/public/index.ts +34 -0
- package/src/hooks/public/usePublicEvent.ts +261 -0
- package/src/hooks/public/usePublicEventLogo.ts +285 -0
- package/src/hooks/public/usePublicRouteParams.ts +259 -0
- package/src/hooks/useAppConfig.ts +94 -0
- package/src/hooks/useComponentPerformance.ts +39 -0
- package/src/hooks/useDataTablePerformance.ts +387 -0
- package/src/hooks/useDataTableState.ts +110 -0
- package/src/hooks/useDebounce.ts +18 -0
- package/src/hooks/useFocusManagement.ts +161 -0
- package/src/hooks/useFocusTrap.ts +155 -0
- package/src/hooks/useInactivityTracker.ts +372 -0
- package/src/hooks/useIsMobile.ts +42 -0
- package/src/hooks/useKeyboardShortcuts.ts +237 -0
- package/src/hooks/useOrganisationPermissions.ts +208 -0
- package/src/hooks/useOrganisationSecurity.ts +262 -0
- package/src/hooks/usePerformanceMonitor.ts +128 -0
- package/src/hooks/usePermissionCache.ts +455 -0
- package/src/hooks/useRBAC.ts +262 -0
- package/src/hooks/useSecureDataAccess.ts +586 -0
- package/src/hooks/useStorage.ts +274 -0
- package/src/hooks/useToast.ts +242 -0
- package/src/hooks/useZodForm.ts +28 -0
- package/src/index.ts +200 -0
- package/src/providers/AuthProvider.tsx +369 -0
- package/src/providers/EventProvider.tsx +324 -0
- package/src/providers/InactivityProvider.tsx +238 -0
- package/src/providers/OrganisationProvider.tsx +588 -0
- package/src/providers/RBACProvider.tsx +622 -0
- package/src/providers/UnifiedAuthProvider.tsx +327 -0
- package/src/providers/__tests__/EventProvider.unit.test.tsx +768 -0
- package/src/providers/__tests__/OrganisationProvider.basic.test.tsx +116 -0
- package/src/providers/__tests__/OrganisationProvider.unit.test.tsx +1312 -0
- package/src/providers/__tests__/UnifiedAuthProvider.inactivity.test.tsx +601 -0
- package/src/providers/__tests__/UnifiedAuthProvider.unit.test.tsx +675 -0
- package/src/providers/__tests__/index.unit.test.ts +78 -0
- package/src/providers/index.ts +15 -0
- package/src/rbac/README.md +885 -0
- package/src/rbac/__tests__/PagePermissionGuard.test.tsx +673 -0
- package/src/rbac/__tests__/README.md +170 -0
- package/src/rbac/__tests__/RoleBasedRouter.test.tsx +709 -0
- package/src/rbac/__tests__/TestContext.tsx +72 -0
- package/src/rbac/__tests__/__mocks__/cache.ts +144 -0
- package/src/rbac/__tests__/__mocks__/supabase.ts +152 -0
- package/src/rbac/__tests__/adapters-hooks-comprehensive.test.tsx +782 -0
- package/src/rbac/__tests__/adapters-hooks.test.tsx +561 -0
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +963 -0
- package/src/rbac/__tests__/adapters.test.tsx +444 -0
- package/src/rbac/__tests__/api.test.ts +620 -0
- package/src/rbac/__tests__/audit-observability-comprehensive.test.ts +792 -0
- package/src/rbac/__tests__/audit-observability.test.ts +549 -0
- package/src/rbac/__tests__/audit.test.ts +616 -0
- package/src/rbac/__tests__/build-contract-compliance-simple.test.ts +230 -0
- package/src/rbac/__tests__/cache-invalidation-comprehensive.test.ts +889 -0
- package/src/rbac/__tests__/cache-invalidation.test.ts +457 -0
- package/src/rbac/__tests__/cache.test.ts +458 -0
- package/src/rbac/__tests__/components-navigation-guard.enhanced.test.tsx +859 -0
- package/src/rbac/__tests__/components-navigation-guard.test.tsx +895 -0
- package/src/rbac/__tests__/components-navigation-provider.test.tsx +692 -0
- package/src/rbac/__tests__/components-page-permission-guard.test.tsx +673 -0
- package/src/rbac/__tests__/components-page-permission-provider.test.tsx +614 -0
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.fixed.test.tsx +836 -0
- package/src/rbac/__tests__/components-permission-enforcer.enhanced.test.tsx +837 -0
- package/src/rbac/__tests__/components-permission-enforcer.test.tsx +825 -0
- package/src/rbac/__tests__/components-role-based-router.test.tsx +709 -0
- package/src/rbac/__tests__/components-secure-data-provider.test.tsx +607 -0
- package/src/rbac/__tests__/config.test.ts +583 -0
- package/src/rbac/__tests__/core-logic-unit.test.ts +190 -0
- package/src/rbac/__tests__/core-permission-logic-comprehensive.test.ts +1467 -0
- package/src/rbac/__tests__/core-permission-logic-fixed.test.ts +151 -0
- package/src/rbac/__tests__/core-permission-logic-simple.test.ts +968 -0
- package/src/rbac/__tests__/core-permission-logic.test.ts +966 -0
- package/src/rbac/__tests__/edge-cases-comprehensive.test.ts +988 -0
- package/src/rbac/__tests__/edge-cases.test.ts +654 -0
- package/src/rbac/__tests__/engine.test.ts +361 -0
- package/src/rbac/__tests__/engine.unit.test.ts +361 -0
- package/src/rbac/__tests__/hooks.enhanced.test.tsx +979 -0
- package/src/rbac/__tests__/hooks.fixed.test.tsx +475 -0
- package/src/rbac/__tests__/hooks.test.tsx +385 -0
- package/src/rbac/__tests__/index.test.ts +269 -0
- package/src/rbac/__tests__/integration.enhanced.test.tsx +824 -0
- package/src/rbac/__tests__/page-permission-guard-super-admin.test.tsx +261 -0
- package/src/rbac/__tests__/performance.enhanced.test.tsx +724 -0
- package/src/rbac/__tests__/permissions.test.ts +383 -0
- package/src/rbac/__tests__/requires-event.test.ts +330 -0
- package/src/rbac/__tests__/scope-isolation-comprehensive.test.ts +1349 -0
- package/src/rbac/__tests__/scope-isolation.test.ts +755 -0
- package/src/rbac/__tests__/secure-client-rls-comprehensive.test.ts +592 -0
- package/src/rbac/__tests__/secure-client-rls.test.ts +377 -0
- package/src/rbac/__tests__/security.test.ts +296 -0
- package/src/rbac/__tests__/setup.ts +228 -0
- package/src/rbac/__tests__/test-utils-enhanced.tsx +400 -0
- package/src/rbac/__tests__/types.test.ts +685 -0
- package/src/rbac/adapters.tsx +726 -0
- package/src/rbac/api.ts +337 -0
- package/src/rbac/audit-enhanced.ts +339 -0
- package/src/rbac/audit.ts +338 -0
- package/src/rbac/cache.ts +213 -0
- package/src/rbac/components/EnhancedNavigationMenu.tsx +294 -0
- package/src/rbac/components/NavigationGuard.tsx +294 -0
- package/src/rbac/components/NavigationProvider.tsx +314 -0
- package/src/rbac/components/PagePermissionGuard.tsx +430 -0
- package/src/rbac/components/PagePermissionProvider.tsx +274 -0
- package/src/rbac/components/PermissionEnforcer.tsx +307 -0
- package/src/rbac/components/RoleBasedRouter.tsx +425 -0
- package/src/rbac/components/SecureDataProvider.tsx +319 -0
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +631 -0
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
- package/src/rbac/components/index.ts +64 -0
- package/src/rbac/config.ts +133 -0
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/engine.ts +1026 -0
- package/src/rbac/eslint-rules.js +285 -0
- package/src/rbac/examples/CompleteRBACExample.tsx +323 -0
- package/src/rbac/examples/EventBasedApp.tsx +238 -0
- package/src/rbac/hooks.ts +555 -0
- package/src/rbac/index.ts +114 -0
- package/src/rbac/permissions.ts +293 -0
- package/src/rbac/secureClient.ts +244 -0
- package/src/rbac/security.ts +346 -0
- package/src/rbac/testing/__tests__/index.test.tsx +342 -0
- package/src/rbac/testing/index.tsx +340 -0
- package/src/rbac/types.ts +341 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +428 -0
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +428 -0
- package/src/rbac/utils/eventContext.ts +83 -0
- package/src/styles/__tests__/styles.unit.test.ts +164 -0
- package/src/styles/core.css +401 -0
- package/src/styles/index.ts +51 -0
- package/src/test-dom-cleanup.test.tsx +38 -0
- package/src/theming/__tests__/README.md +335 -0
- package/src/theming/__tests__/runtime.accessibility.test.ts +474 -0
- package/src/theming/__tests__/runtime.error.test.ts +616 -0
- package/src/theming/__tests__/runtime.integration.test.ts +376 -0
- package/src/theming/__tests__/runtime.performance.test.ts +411 -0
- package/src/theming/__tests__/runtime.unit.test.ts +470 -0
- package/src/theming/runtime.ts +187 -0
- package/src/types/__tests__/database.unit.test.ts +489 -0
- package/src/types/__tests__/guards.unit.test.ts +146 -0
- package/src/types/__tests__/index.unit.test.ts +77 -0
- package/src/types/__tests__/organisation.unit.test.ts +713 -0
- package/src/types/__tests__/rbac.unit.test.ts +621 -0
- package/src/types/__tests__/security.unit.test.ts +347 -0
- package/src/types/__tests__/supabase.unit.test.ts +658 -0
- package/src/types/__tests__/theme.unit.test.ts +218 -0
- package/src/types/__tests__/unified.unit.test.ts +537 -0
- package/src/types/__tests__/validation.unit.test.ts +616 -0
- package/src/types/database.ts +472 -0
- package/src/types/guards.ts +30 -0
- package/src/types/index.ts +25 -0
- package/src/types/organisation.ts +184 -0
- package/src/types/security.ts +70 -0
- package/src/types/supabase.ts +166 -0
- package/src/types/theme.ts +6 -0
- package/src/types/unified.ts +262 -0
- package/src/types/validation.ts +164 -0
- package/src/types/vitest-globals.d.ts +43 -0
- package/src/utils/__mocks__/supabaseMock.ts +75 -0
- package/src/utils/__mocks__/supabaseMock.tsx +198 -0
- package/src/utils/__tests__/appConfig.unit.test.ts +55 -0
- package/src/utils/__tests__/appNameResolver.unit.test.ts +137 -0
- package/src/utils/__tests__/audit.unit.test.ts +69 -0
- package/src/utils/__tests__/auth-utils.unit.test.ts +70 -0
- package/src/utils/__tests__/bundleAnalysis.unit.test.ts +317 -0
- package/src/utils/__tests__/cn.unit.test.ts +34 -0
- package/src/utils/__tests__/deviceFingerprint.unit.test.ts +480 -0
- package/src/utils/__tests__/dynamicUtils.unit.test.ts +322 -0
- package/src/utils/__tests__/formatDate.unit.test.ts +109 -0
- package/src/utils/__tests__/formatting.unit.test.ts +66 -0
- package/src/utils/__tests__/index.unit.test.ts +251 -0
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +309 -0
- package/src/utils/__tests__/organisationContext.unit.test.ts +192 -0
- package/src/utils/__tests__/performanceBudgets.unit.test.ts +259 -0
- package/src/utils/__tests__/permissionTypes.unit.test.ts +250 -0
- package/src/utils/__tests__/permissionUtils.unit.test.ts +362 -0
- package/src/utils/__tests__/sanitization.unit.test.ts +346 -0
- package/src/utils/__tests__/schemaUtils.unit.test.ts +441 -0
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +334 -0
- package/src/utils/__tests__/secureErrors.unit.test.ts +377 -0
- package/src/utils/__tests__/secureStorage.unit.test.ts +293 -0
- package/src/utils/__tests__/security.unit.test.ts +127 -0
- package/src/utils/__tests__/securityMonitor.unit.test.ts +280 -0
- package/src/utils/__tests__/sessionTracking.unit.test.ts +370 -0
- package/src/utils/__tests__/validation.unit.test.ts +84 -0
- package/src/utils/__tests__/validationUtils.unit.test.ts +571 -0
- package/src/utils/appConfig.ts +47 -0
- package/src/utils/appIdResolver.ts +130 -0
- package/src/utils/appNameResolver.ts +190 -0
- package/src/utils/audit.ts +127 -0
- package/src/utils/auth-utils.ts +96 -0
- package/src/utils/bundleAnalysis.ts +129 -0
- package/src/utils/cn.ts +7 -0
- package/src/utils/debugLogger.ts +46 -0
- package/src/utils/deviceFingerprint.ts +215 -0
- package/src/utils/dynamicUtils.ts +105 -0
- package/src/utils/formatting.ts +77 -0
- package/src/utils/index.ts +145 -0
- package/src/utils/lazyLoad.tsx +44 -0
- package/src/utils/organisationContext.ts +135 -0
- package/src/utils/performanceBenchmark.ts +64 -0
- package/src/utils/performanceBudgets.ts +111 -0
- package/src/utils/permissionTypes.ts +37 -0
- package/src/utils/permissionUtils.ts +31 -0
- package/src/utils/print/PrintDataProcessor.ts +390 -0
- package/src/utils/print/__tests__/PrintDataProcessor.unit.test.ts +219 -0
- package/src/utils/print/__tests__/usePrintOptimization.unit.test.tsx +353 -0
- package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +397 -0
- package/src/utils/print/index.ts +29 -0
- package/src/utils/print/types.ts +196 -0
- package/src/utils/print/usePrintOptimization.ts +272 -0
- package/src/utils/sanitization.ts +264 -0
- package/src/utils/schemaUtils.ts +37 -0
- package/src/utils/secureDataAccess.ts +361 -0
- package/src/utils/secureErrors.ts +79 -0
- package/src/utils/secureStorage.ts +244 -0
- package/src/utils/security.ts +156 -0
- package/src/utils/securityMonitor.ts +45 -0
- package/src/utils/sessionTracking.ts +170 -0
- package/src/utils/storage/README.md +348 -0
- package/src/utils/storage/__tests__/config.unit.test.ts +206 -0
- package/src/utils/storage/__tests__/helpers.unit.test.ts +646 -0
- package/src/utils/storage/__tests__/index.unit.test.ts +167 -0
- package/src/utils/storage/__tests__/types.unit.test.ts +441 -0
- package/src/utils/storage/config.ts +100 -0
- package/src/utils/storage/helpers.ts +359 -0
- package/src/utils/storage/index.ts +36 -0
- package/src/utils/storage/types.ts +90 -0
- package/src/utils/validation.ts +111 -0
- package/src/utils/validationUtils.ts +120 -0
- package/src/validation/__tests__/common.unit.test.ts +101 -0
- package/src/validation/__tests__/csrf.unit.test.ts +302 -0
- package/src/validation/__tests__/passwordSchema.unit.test.ts +98 -0
- package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +466 -0
- package/src/validation/common.ts +53 -0
- package/src/validation/csrf.ts +214 -0
- package/src/validation/index.ts +43 -0
- package/src/validation/passwordSchema.ts +125 -0
- package/src/validation/sanitization.ts +96 -0
- package/src/validation/schemaUtils.ts +42 -0
- package/src/validation/sqlInjectionProtection.ts +242 -0
- package/src/validation/user.ts +34 -0
|
@@ -0,0 +1,1345 @@
|
|
|
1
|
+
import {
|
|
2
|
+
createAuditManager,
|
|
3
|
+
emitAuditEvent,
|
|
4
|
+
setGlobalAuditManager
|
|
5
|
+
} from "./chunk-7BNPOCLL.js";
|
|
6
|
+
|
|
7
|
+
// src/rbac/types.ts
|
|
8
|
+
var RBACError = class extends Error {
|
|
9
|
+
constructor(message, code, context) {
|
|
10
|
+
super(message);
|
|
11
|
+
this.code = code;
|
|
12
|
+
this.context = context;
|
|
13
|
+
this.name = "RBACError";
|
|
14
|
+
}
|
|
15
|
+
};
|
|
16
|
+
var OrganisationContextRequiredError = class extends RBACError {
|
|
17
|
+
constructor() {
|
|
18
|
+
super(
|
|
19
|
+
"Organisation context is required for this operation",
|
|
20
|
+
"ORGANISATION_CONTEXT_REQUIRED"
|
|
21
|
+
);
|
|
22
|
+
this.name = "OrganisationContextRequiredError";
|
|
23
|
+
}
|
|
24
|
+
};
|
|
25
|
+
var RBACNotInitializedError = class extends RBACError {
|
|
26
|
+
constructor() {
|
|
27
|
+
super(
|
|
28
|
+
"RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup",
|
|
29
|
+
"RBAC_NOT_INITIALIZED"
|
|
30
|
+
);
|
|
31
|
+
this.name = "RBACNotInitializedError";
|
|
32
|
+
}
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
// src/rbac/cache.ts
|
|
36
|
+
var RBACCache = class {
|
|
37
|
+
constructor() {
|
|
38
|
+
this.cache = /* @__PURE__ */ new Map();
|
|
39
|
+
this.TTL = 60 * 1e3;
|
|
40
|
+
// 60 seconds
|
|
41
|
+
this.invalidationCallbacks = /* @__PURE__ */ new Set();
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Get a value from the cache
|
|
45
|
+
*
|
|
46
|
+
* @param key - Cache key
|
|
47
|
+
* @returns Cached value or null if not found/expired
|
|
48
|
+
*/
|
|
49
|
+
get(key) {
|
|
50
|
+
const entry = this.cache.get(key);
|
|
51
|
+
if (!entry) {
|
|
52
|
+
return null;
|
|
53
|
+
}
|
|
54
|
+
if (Date.now() > entry.expires) {
|
|
55
|
+
this.cache.delete(key);
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
return entry.data;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Set a value in the cache
|
|
62
|
+
*
|
|
63
|
+
* @param key - Cache key
|
|
64
|
+
* @param data - Data to cache
|
|
65
|
+
* @param ttl - Time to live in milliseconds (defaults to 60s)
|
|
66
|
+
*/
|
|
67
|
+
set(key, data, ttl = this.TTL) {
|
|
68
|
+
const expires = ttl <= 0 ? Date.now() - 1 : Date.now() + ttl;
|
|
69
|
+
this.cache.set(key, {
|
|
70
|
+
data,
|
|
71
|
+
expires
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Delete a specific key from the cache
|
|
76
|
+
*
|
|
77
|
+
* @param key - Cache key to delete
|
|
78
|
+
*/
|
|
79
|
+
delete(key) {
|
|
80
|
+
this.cache.delete(key);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Invalidate cache entries matching a pattern
|
|
84
|
+
*
|
|
85
|
+
* @param pattern - Pattern to match against cache keys
|
|
86
|
+
*/
|
|
87
|
+
invalidate(pattern) {
|
|
88
|
+
const keysToDelete = [];
|
|
89
|
+
for (const key of this.cache.keys()) {
|
|
90
|
+
if (key.includes(pattern)) {
|
|
91
|
+
keysToDelete.push(key);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
keysToDelete.forEach((key) => this.cache.delete(key));
|
|
95
|
+
this.invalidationCallbacks.forEach((callback) => callback(pattern));
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Clear all cache entries
|
|
99
|
+
*/
|
|
100
|
+
clear() {
|
|
101
|
+
this.cache.clear();
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Get cache statistics
|
|
105
|
+
*/
|
|
106
|
+
getStats() {
|
|
107
|
+
return {
|
|
108
|
+
size: this.cache.size,
|
|
109
|
+
ttl: this.TTL,
|
|
110
|
+
keys: Array.from(this.cache.keys())
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Add an invalidation callback
|
|
115
|
+
*
|
|
116
|
+
* @param callback - Function to call when cache is invalidated
|
|
117
|
+
*/
|
|
118
|
+
onInvalidate(callback) {
|
|
119
|
+
this.invalidationCallbacks.add(callback);
|
|
120
|
+
return () => {
|
|
121
|
+
this.invalidationCallbacks.delete(callback);
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Generate cache key for permission check
|
|
126
|
+
*
|
|
127
|
+
* @param key - Permission cache key object
|
|
128
|
+
* @returns String cache key
|
|
129
|
+
*/
|
|
130
|
+
static generatePermissionKey(key) {
|
|
131
|
+
const parts = [
|
|
132
|
+
"perm",
|
|
133
|
+
key.userId,
|
|
134
|
+
key.organisationId || "null",
|
|
135
|
+
key.eventId || "null",
|
|
136
|
+
key.appId || "null"
|
|
137
|
+
];
|
|
138
|
+
return parts.join(":");
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Generate cache key for access level
|
|
142
|
+
*
|
|
143
|
+
* @param userId - User ID
|
|
144
|
+
* @param organisationId - Organisation ID
|
|
145
|
+
* @param eventId - Event ID (optional)
|
|
146
|
+
* @param appId - App ID (optional)
|
|
147
|
+
* @returns String cache key
|
|
148
|
+
*/
|
|
149
|
+
static generateAccessLevelKey(userId, organisationId, eventId, appId) {
|
|
150
|
+
const parts = [
|
|
151
|
+
"access",
|
|
152
|
+
userId,
|
|
153
|
+
organisationId,
|
|
154
|
+
eventId || "null",
|
|
155
|
+
appId || "null"
|
|
156
|
+
];
|
|
157
|
+
return parts.join(":");
|
|
158
|
+
}
|
|
159
|
+
/**
|
|
160
|
+
* Generate cache key for permission map
|
|
161
|
+
*
|
|
162
|
+
* @param userId - User ID
|
|
163
|
+
* @param organisationId - Organisation ID
|
|
164
|
+
* @param eventId - Event ID (optional)
|
|
165
|
+
* @param appId - App ID (optional)
|
|
166
|
+
* @returns String cache key
|
|
167
|
+
*/
|
|
168
|
+
static generatePermissionMapKey(userId, organisationId, eventId, appId) {
|
|
169
|
+
const parts = [
|
|
170
|
+
"map",
|
|
171
|
+
userId,
|
|
172
|
+
organisationId,
|
|
173
|
+
eventId || "null",
|
|
174
|
+
appId || "null"
|
|
175
|
+
];
|
|
176
|
+
return parts.join(":");
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
var rbacCache = new RBACCache();
|
|
180
|
+
var CACHE_PATTERNS = {
|
|
181
|
+
USER: (userId) => `user:${userId}`,
|
|
182
|
+
ORGANISATION: (organisationId) => `org:${organisationId}`,
|
|
183
|
+
EVENT: (eventId) => `event:${eventId}`,
|
|
184
|
+
APP: (appId) => `app:${appId}`,
|
|
185
|
+
PERMISSION: (userId, organisationId) => `perm:${userId}:${organisationId}`
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
// src/rbac/security.ts
|
|
189
|
+
var RBACSecurityValidator = class {
|
|
190
|
+
/**
|
|
191
|
+
* Validate permission string format
|
|
192
|
+
* @param permission - Permission string to validate
|
|
193
|
+
* @returns True if valid, false otherwise
|
|
194
|
+
*/
|
|
195
|
+
static validatePermission(permission) {
|
|
196
|
+
if (typeof permission !== "string" || permission.length === 0) {
|
|
197
|
+
return false;
|
|
198
|
+
}
|
|
199
|
+
const permissionRegex = /^(read|create|update|delete|manage):[a-z0-9._-]+$/;
|
|
200
|
+
return permissionRegex.test(permission);
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Validate UUID format
|
|
204
|
+
* @param uuid - UUID string to validate
|
|
205
|
+
* @returns True if valid, false otherwise
|
|
206
|
+
*/
|
|
207
|
+
static validateUUID(uuid) {
|
|
208
|
+
if (typeof uuid !== "string" || uuid.length === 0) {
|
|
209
|
+
return false;
|
|
210
|
+
}
|
|
211
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
212
|
+
return uuidRegex.test(uuid);
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Validate scope object
|
|
216
|
+
* @param scope - Scope object to validate
|
|
217
|
+
* @returns True if valid, false otherwise
|
|
218
|
+
*/
|
|
219
|
+
static validateScope(scope) {
|
|
220
|
+
if (!scope || typeof scope !== "object") {
|
|
221
|
+
return false;
|
|
222
|
+
}
|
|
223
|
+
if (scope.organisationId && !this.validateUUID(scope.organisationId)) {
|
|
224
|
+
return false;
|
|
225
|
+
}
|
|
226
|
+
if (scope.eventId && typeof scope.eventId !== "string") {
|
|
227
|
+
return false;
|
|
228
|
+
}
|
|
229
|
+
if (scope.appId && !this.validateUUID(scope.appId)) {
|
|
230
|
+
return false;
|
|
231
|
+
}
|
|
232
|
+
return !!(scope.organisationId || scope.eventId || scope.appId);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Sanitize input string to prevent injection attacks
|
|
236
|
+
* @param input - Input string to sanitize
|
|
237
|
+
* @returns Sanitized string
|
|
238
|
+
*/
|
|
239
|
+
static sanitizeInput(input) {
|
|
240
|
+
if (typeof input !== "string") {
|
|
241
|
+
return "";
|
|
242
|
+
}
|
|
243
|
+
return input.replace(/<[^>]*>/g, "").replace(/[<>\"'&]/g, "").replace(/[;()]/g, "").replace(/javascript:/gi, "").replace(/data:/gi, "").trim();
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Validate user ID format
|
|
247
|
+
* @param userId - User ID to validate
|
|
248
|
+
* @returns True if valid, false otherwise
|
|
249
|
+
*/
|
|
250
|
+
static validateUserId(userId) {
|
|
251
|
+
return this.validateUUID(userId);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Check if permission is a wildcard permission
|
|
255
|
+
* @param permission - Permission string to check
|
|
256
|
+
* @returns True if wildcard, false otherwise
|
|
257
|
+
*/
|
|
258
|
+
static isWildcardPermission(permission) {
|
|
259
|
+
return permission.includes("*") || permission.endsWith(":*");
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Validate permission hierarchy
|
|
263
|
+
* @param permission - Permission to validate
|
|
264
|
+
* @param requiredOperation - Required operation
|
|
265
|
+
* @returns True if permission matches or is higher in hierarchy
|
|
266
|
+
*/
|
|
267
|
+
static validatePermissionHierarchy(permission, requiredOperation) {
|
|
268
|
+
if (!this.validatePermission(permission)) {
|
|
269
|
+
return false;
|
|
270
|
+
}
|
|
271
|
+
const [operation] = permission.split(":");
|
|
272
|
+
const hierarchy = ["read", "create", "update", "delete", "manage"];
|
|
273
|
+
const permissionLevel = hierarchy.indexOf(operation);
|
|
274
|
+
const requiredLevel = hierarchy.indexOf(requiredOperation);
|
|
275
|
+
if (permissionLevel === -1 || requiredLevel === -1) {
|
|
276
|
+
return false;
|
|
277
|
+
}
|
|
278
|
+
return permissionLevel >= requiredLevel;
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Rate limiting check (placeholder for future implementation)
|
|
282
|
+
* @param userId - User ID
|
|
283
|
+
* @param operation - Operation being performed
|
|
284
|
+
* @returns True if within rate limit, false otherwise
|
|
285
|
+
*/
|
|
286
|
+
static async checkRateLimit(userId, operation) {
|
|
287
|
+
return true;
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Validate context requirements for security
|
|
291
|
+
* @param scope - Scope object
|
|
292
|
+
* @param appId - Application ID
|
|
293
|
+
* @returns True if context is valid, false otherwise
|
|
294
|
+
*/
|
|
295
|
+
static validateContextRequirements(scope, appId) {
|
|
296
|
+
if (!scope.organisationId) {
|
|
297
|
+
return false;
|
|
298
|
+
}
|
|
299
|
+
if (appId && scope.appId === appId) {
|
|
300
|
+
if (!scope.eventId) {
|
|
301
|
+
return false;
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
return true;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Log security event for monitoring
|
|
308
|
+
* @param event - Security event details
|
|
309
|
+
*/
|
|
310
|
+
static logSecurityEvent(event) {
|
|
311
|
+
const securityEvent = {
|
|
312
|
+
...event,
|
|
313
|
+
timestamp: event.timestamp || /* @__PURE__ */ new Date(),
|
|
314
|
+
severity: this.getEventSeverity(event.type)
|
|
315
|
+
};
|
|
316
|
+
if (false) {
|
|
317
|
+
console.warn("[RBAC Security]", securityEvent);
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Get severity level for security event
|
|
322
|
+
* @param eventType - Type of security event
|
|
323
|
+
* @returns Severity level
|
|
324
|
+
*/
|
|
325
|
+
static getEventSeverity(eventType) {
|
|
326
|
+
switch (eventType) {
|
|
327
|
+
case "permission_denied":
|
|
328
|
+
return "low";
|
|
329
|
+
case "invalid_input":
|
|
330
|
+
return "medium";
|
|
331
|
+
case "rate_limit_exceeded":
|
|
332
|
+
return "medium";
|
|
333
|
+
case "suspicious_activity":
|
|
334
|
+
return "high";
|
|
335
|
+
default:
|
|
336
|
+
return "low";
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
};
|
|
340
|
+
var DEFAULT_SECURITY_CONFIG = {
|
|
341
|
+
enableInputValidation: true,
|
|
342
|
+
enableRateLimiting: true,
|
|
343
|
+
enableAuditLogging: true,
|
|
344
|
+
maxPermissionChecksPerMinute: 100,
|
|
345
|
+
suspiciousActivityThreshold: 10
|
|
346
|
+
};
|
|
347
|
+
var RBACSecurityMiddleware = class {
|
|
348
|
+
constructor(config = DEFAULT_SECURITY_CONFIG) {
|
|
349
|
+
this.config = config;
|
|
350
|
+
}
|
|
351
|
+
/**
|
|
352
|
+
* Validate input before processing
|
|
353
|
+
* @param input - Input to validate
|
|
354
|
+
* @param context - Security context
|
|
355
|
+
* @returns Validation result
|
|
356
|
+
*/
|
|
357
|
+
async validateInput(input, context) {
|
|
358
|
+
const errors = [];
|
|
359
|
+
if (!this.config.enableInputValidation) {
|
|
360
|
+
return { isValid: true, errors: [] };
|
|
361
|
+
}
|
|
362
|
+
if (!RBACSecurityValidator.validateUserId(context.userId)) {
|
|
363
|
+
errors.push("Invalid user ID format");
|
|
364
|
+
}
|
|
365
|
+
if (!RBACSecurityValidator.validateUUID(context.organisationId)) {
|
|
366
|
+
errors.push("Invalid organisation ID format");
|
|
367
|
+
}
|
|
368
|
+
if (input.permission && !RBACSecurityValidator.validatePermission(input.permission)) {
|
|
369
|
+
errors.push("Invalid permission format");
|
|
370
|
+
}
|
|
371
|
+
if (input.scope && !RBACSecurityValidator.validateScope(input.scope)) {
|
|
372
|
+
errors.push("Invalid scope format");
|
|
373
|
+
}
|
|
374
|
+
if (errors.length > 0) {
|
|
375
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
376
|
+
type: "invalid_input",
|
|
377
|
+
userId: context.userId,
|
|
378
|
+
details: { errors, input: this.sanitizeInput(JSON.stringify(input)) }
|
|
379
|
+
});
|
|
380
|
+
}
|
|
381
|
+
return {
|
|
382
|
+
isValid: errors.length === 0,
|
|
383
|
+
errors
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Check rate limiting
|
|
388
|
+
* @param context - Security context
|
|
389
|
+
* @returns Rate limit check result
|
|
390
|
+
*/
|
|
391
|
+
async checkRateLimit(context) {
|
|
392
|
+
if (!this.config.enableRateLimiting) {
|
|
393
|
+
return { isAllowed: true, remaining: this.config.maxPermissionChecksPerMinute };
|
|
394
|
+
}
|
|
395
|
+
const isAllowed = await RBACSecurityValidator.checkRateLimit(
|
|
396
|
+
context.userId,
|
|
397
|
+
"permission_check"
|
|
398
|
+
);
|
|
399
|
+
return {
|
|
400
|
+
isAllowed,
|
|
401
|
+
remaining: this.config.maxPermissionChecksPerMinute
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
/**
|
|
405
|
+
* Sanitize input data
|
|
406
|
+
* @param input - Input to sanitize
|
|
407
|
+
* @returns Sanitized input
|
|
408
|
+
*/
|
|
409
|
+
sanitizeInput(input) {
|
|
410
|
+
return RBACSecurityValidator.sanitizeInput(input);
|
|
411
|
+
}
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
// src/rbac/engine.ts
|
|
415
|
+
var RBACEngine = class {
|
|
416
|
+
constructor(supabase) {
|
|
417
|
+
this.supabase = supabase;
|
|
418
|
+
this.securityMiddleware = new RBACSecurityMiddleware(DEFAULT_SECURITY_CONFIG);
|
|
419
|
+
}
|
|
420
|
+
/**
|
|
421
|
+
* Check if a user has a specific permission
|
|
422
|
+
*
|
|
423
|
+
* @param input - Permission check input
|
|
424
|
+
* @param securityContext - Optional security context for enhanced validation
|
|
425
|
+
* @returns Promise resolving to permission result
|
|
426
|
+
*/
|
|
427
|
+
async isPermitted(input, securityContext) {
|
|
428
|
+
const startTime = Date.now();
|
|
429
|
+
const { userId, permission, scope, pageId } = input;
|
|
430
|
+
try {
|
|
431
|
+
if (securityContext) {
|
|
432
|
+
const validation = await this.securityMiddleware.validateInput(input, securityContext);
|
|
433
|
+
if (!validation.isValid) {
|
|
434
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
435
|
+
type: "invalid_input",
|
|
436
|
+
userId,
|
|
437
|
+
details: { errors: validation.errors, input: JSON.stringify(input) }
|
|
438
|
+
});
|
|
439
|
+
return false;
|
|
440
|
+
}
|
|
441
|
+
const rateLimit = await this.securityMiddleware.checkRateLimit(securityContext);
|
|
442
|
+
if (!rateLimit.isAllowed) {
|
|
443
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
444
|
+
type: "rate_limit_exceeded",
|
|
445
|
+
userId,
|
|
446
|
+
details: { remaining: rateLimit.remaining }
|
|
447
|
+
});
|
|
448
|
+
return false;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
if (securityContext) {
|
|
452
|
+
if (!RBACSecurityValidator.validateUserId(userId)) {
|
|
453
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
454
|
+
type: "invalid_input",
|
|
455
|
+
userId,
|
|
456
|
+
details: { error: "Invalid user ID format" }
|
|
457
|
+
});
|
|
458
|
+
return false;
|
|
459
|
+
}
|
|
460
|
+
if (!RBACSecurityValidator.validatePermission(permission)) {
|
|
461
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
462
|
+
type: "invalid_input",
|
|
463
|
+
userId,
|
|
464
|
+
details: { error: "Invalid permission format", permission }
|
|
465
|
+
});
|
|
466
|
+
return false;
|
|
467
|
+
}
|
|
468
|
+
if (!RBACSecurityValidator.validateScope(scope)) {
|
|
469
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
470
|
+
type: "invalid_input",
|
|
471
|
+
userId,
|
|
472
|
+
details: { error: "Invalid scope format", scope }
|
|
473
|
+
});
|
|
474
|
+
return false;
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
const isSuperAdmin2 = await this.checkSuperAdmin(userId);
|
|
478
|
+
if (isSuperAdmin2) {
|
|
479
|
+
const duration = Date.now() - startTime;
|
|
480
|
+
if (scope.organisationId) {
|
|
481
|
+
const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
|
|
482
|
+
await emitAuditEvent({
|
|
483
|
+
type: "permission_check",
|
|
484
|
+
userId,
|
|
485
|
+
organisationId: scope.organisationId,
|
|
486
|
+
eventId: scope.eventId,
|
|
487
|
+
appId: scope.appId,
|
|
488
|
+
pageId: resolvedPageId,
|
|
489
|
+
permission,
|
|
490
|
+
decision: true,
|
|
491
|
+
source: "api",
|
|
492
|
+
bypass: true,
|
|
493
|
+
duration_ms: duration
|
|
494
|
+
});
|
|
495
|
+
}
|
|
496
|
+
return true;
|
|
497
|
+
}
|
|
498
|
+
const validatedScope = await this.validateContextRequirements(scope, scope.appId);
|
|
499
|
+
if (!validatedScope) {
|
|
500
|
+
const duration = Date.now() - startTime;
|
|
501
|
+
if (scope.organisationId) {
|
|
502
|
+
const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
|
|
503
|
+
await emitAuditEvent({
|
|
504
|
+
type: "permission_denied",
|
|
505
|
+
userId,
|
|
506
|
+
organisationId: scope.organisationId,
|
|
507
|
+
eventId: scope.eventId,
|
|
508
|
+
appId: scope.appId,
|
|
509
|
+
pageId: resolvedPageId,
|
|
510
|
+
permission,
|
|
511
|
+
source: "api",
|
|
512
|
+
metadata: {
|
|
513
|
+
reason: "invalid_context_requirements",
|
|
514
|
+
app_requires_event: scope.appId ? await this.getAppConfig(scope.appId).then((config) => config?.requires_event) : null
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
return false;
|
|
519
|
+
}
|
|
520
|
+
const grants = await this.collectActiveGrants(userId, validatedScope, pageId);
|
|
521
|
+
console.log("[RBACEngine] Collected grants:", grants);
|
|
522
|
+
const denies = grants.filter((g) => g.type === "deny");
|
|
523
|
+
console.log("[RBACEngine] Deny grants:", denies);
|
|
524
|
+
for (const deny of denies) {
|
|
525
|
+
const matches = this.permissionMatches(deny.permission, permission);
|
|
526
|
+
console.log("[RBACEngine] Checking deny:", {
|
|
527
|
+
denyPermission: deny.permission,
|
|
528
|
+
requestedPermission: permission,
|
|
529
|
+
matches
|
|
530
|
+
});
|
|
531
|
+
if (matches) {
|
|
532
|
+
const duration = Date.now() - startTime;
|
|
533
|
+
console.log("[RBACEngine] Permission DENIED by explicit deny rule");
|
|
534
|
+
if (scope.organisationId) {
|
|
535
|
+
const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
|
|
536
|
+
await emitAuditEvent({
|
|
537
|
+
type: "permission_denied",
|
|
538
|
+
userId,
|
|
539
|
+
organisationId: scope.organisationId,
|
|
540
|
+
eventId: scope.eventId,
|
|
541
|
+
appId: scope.appId,
|
|
542
|
+
pageId: resolvedPageId,
|
|
543
|
+
permission,
|
|
544
|
+
source: "api"
|
|
545
|
+
});
|
|
546
|
+
}
|
|
547
|
+
return false;
|
|
548
|
+
}
|
|
549
|
+
}
|
|
550
|
+
const allows = grants.filter((g) => g.type === "allow");
|
|
551
|
+
console.log("[RBACEngine] Allow grants:", allows);
|
|
552
|
+
let hasPermission2 = false;
|
|
553
|
+
const scopeOrder = ["page", "eventApp", "organisation", "global"];
|
|
554
|
+
for (const scopeType of scopeOrder) {
|
|
555
|
+
const scopeAllows = allows.filter((g) => g.scope === scopeType);
|
|
556
|
+
console.log(`[RBACEngine] Checking ${scopeType} allows:`, scopeAllows);
|
|
557
|
+
for (const allow of scopeAllows) {
|
|
558
|
+
console.log(`[RBACEngine] About to check permission match for ${scopeType}:`, {
|
|
559
|
+
allowPermission: allow.permission,
|
|
560
|
+
requestedPermission: permission,
|
|
561
|
+
scopeType
|
|
562
|
+
});
|
|
563
|
+
const matches = this.permissionMatches(allow.permission, permission);
|
|
564
|
+
console.log(`[RBACEngine] Permission match result:`, {
|
|
565
|
+
scopeType,
|
|
566
|
+
allowPermission: allow.permission,
|
|
567
|
+
requestedPermission: permission,
|
|
568
|
+
matches
|
|
569
|
+
});
|
|
570
|
+
if (matches) {
|
|
571
|
+
console.log(`[RBACEngine] Permission GRANTED by ${scopeType} allow rule`);
|
|
572
|
+
hasPermission2 = true;
|
|
573
|
+
break;
|
|
574
|
+
}
|
|
575
|
+
}
|
|
576
|
+
if (hasPermission2) break;
|
|
577
|
+
}
|
|
578
|
+
const finalDecision = hasPermission2;
|
|
579
|
+
const _duration = Date.now() - startTime;
|
|
580
|
+
console.log("[RBACEngine] Final decision:", {
|
|
581
|
+
userId,
|
|
582
|
+
permission,
|
|
583
|
+
pageId,
|
|
584
|
+
hasPermission: hasPermission2,
|
|
585
|
+
grantsCount: grants.length,
|
|
586
|
+
allowsCount: allows.length,
|
|
587
|
+
deniesCount: denies.length,
|
|
588
|
+
duration: _duration
|
|
589
|
+
});
|
|
590
|
+
if (scope.organisationId) {
|
|
591
|
+
const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
|
|
592
|
+
await emitAuditEvent({
|
|
593
|
+
type: "permission_check",
|
|
594
|
+
userId,
|
|
595
|
+
organisationId: scope.organisationId,
|
|
596
|
+
eventId: scope.eventId,
|
|
597
|
+
appId: scope.appId,
|
|
598
|
+
pageId: resolvedPageId,
|
|
599
|
+
permission,
|
|
600
|
+
decision: finalDecision,
|
|
601
|
+
source: "api",
|
|
602
|
+
duration_ms: _duration
|
|
603
|
+
});
|
|
604
|
+
}
|
|
605
|
+
return finalDecision;
|
|
606
|
+
} catch (error) {
|
|
607
|
+
RBACSecurityValidator.logSecurityEvent({
|
|
608
|
+
type: "suspicious_activity",
|
|
609
|
+
userId,
|
|
610
|
+
details: {
|
|
611
|
+
error: error instanceof Error ? error.message : "Unknown error",
|
|
612
|
+
permission,
|
|
613
|
+
scope: JSON.stringify(scope)
|
|
614
|
+
}
|
|
615
|
+
});
|
|
616
|
+
return false;
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
/**
|
|
620
|
+
* Get user's access level in a scope
|
|
621
|
+
*
|
|
622
|
+
* @param input - Access level input
|
|
623
|
+
* @returns Promise resolving to access level
|
|
624
|
+
*/
|
|
625
|
+
async getAccessLevel(input) {
|
|
626
|
+
const { userId, scope } = input;
|
|
627
|
+
const isSuperAdmin2 = await this.checkSuperAdmin(userId);
|
|
628
|
+
if (isSuperAdmin2) {
|
|
629
|
+
return "super";
|
|
630
|
+
}
|
|
631
|
+
const validatedScope = await this.validateContextRequirements(scope, scope.appId);
|
|
632
|
+
if (!validatedScope) {
|
|
633
|
+
return "viewer";
|
|
634
|
+
}
|
|
635
|
+
const cacheKey = RBACCache.generateAccessLevelKey(
|
|
636
|
+
userId,
|
|
637
|
+
validatedScope.organisationId,
|
|
638
|
+
validatedScope.eventId,
|
|
639
|
+
validatedScope.appId
|
|
640
|
+
);
|
|
641
|
+
const cached = rbacCache.get(cacheKey);
|
|
642
|
+
if (cached) {
|
|
643
|
+
return cached;
|
|
644
|
+
}
|
|
645
|
+
const orgRole = await this.getOrganisationRole(userId, validatedScope.organisationId);
|
|
646
|
+
if (orgRole === "org_admin") {
|
|
647
|
+
rbacCache.set(cacheKey, "admin");
|
|
648
|
+
return "admin";
|
|
649
|
+
}
|
|
650
|
+
if (validatedScope.eventId && validatedScope.appId) {
|
|
651
|
+
const eventRole = await this.getEventAppRole(userId, validatedScope.eventId, validatedScope.appId);
|
|
652
|
+
if (eventRole === "event_admin") {
|
|
653
|
+
rbacCache.set(cacheKey, "admin");
|
|
654
|
+
return "admin";
|
|
655
|
+
}
|
|
656
|
+
if (eventRole === "planner") {
|
|
657
|
+
rbacCache.set(cacheKey, "planner");
|
|
658
|
+
return "planner";
|
|
659
|
+
}
|
|
660
|
+
if (eventRole === "participant") {
|
|
661
|
+
rbacCache.set(cacheKey, "participant");
|
|
662
|
+
return "participant";
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
rbacCache.set(cacheKey, "viewer");
|
|
666
|
+
return "viewer";
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Get user's permission map for a scope
|
|
670
|
+
*
|
|
671
|
+
* @param input - Permission map input
|
|
672
|
+
* @returns Promise resolving to permission map
|
|
673
|
+
*/
|
|
674
|
+
async getPermissionMap(input) {
|
|
675
|
+
const { userId, scope } = input;
|
|
676
|
+
const isSuperAdmin2 = await this.checkSuperAdmin(userId);
|
|
677
|
+
if (isSuperAdmin2) {
|
|
678
|
+
return {};
|
|
679
|
+
}
|
|
680
|
+
const validatedScope = await this.validateContextRequirements(scope, scope.appId);
|
|
681
|
+
if (!validatedScope) {
|
|
682
|
+
return {};
|
|
683
|
+
}
|
|
684
|
+
const cacheKey = RBACCache.generatePermissionMapKey(
|
|
685
|
+
userId,
|
|
686
|
+
validatedScope.organisationId,
|
|
687
|
+
validatedScope.eventId,
|
|
688
|
+
validatedScope.appId
|
|
689
|
+
);
|
|
690
|
+
const cached = rbacCache.get(cacheKey);
|
|
691
|
+
if (cached) {
|
|
692
|
+
return cached;
|
|
693
|
+
}
|
|
694
|
+
const permissionMap = {};
|
|
695
|
+
if (validatedScope.appId) {
|
|
696
|
+
const { data: pages } = await this.supabase.from("rbac_app_pages").select("id, page_name").eq("app_id", validatedScope.appId);
|
|
697
|
+
if (pages) {
|
|
698
|
+
for (const page of pages) {
|
|
699
|
+
const operations = [];
|
|
700
|
+
for (const operation of ["read", "create", "update", "delete", "manage"]) {
|
|
701
|
+
const hasPermission2 = await this.isPermitted({
|
|
702
|
+
userId,
|
|
703
|
+
scope: validatedScope,
|
|
704
|
+
permission: `${operation}:${page.page_name}`,
|
|
705
|
+
pageId: page.id
|
|
706
|
+
});
|
|
707
|
+
if (hasPermission2) {
|
|
708
|
+
operations.push(operation);
|
|
709
|
+
}
|
|
710
|
+
}
|
|
711
|
+
permissionMap[page.id] = operations;
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
rbacCache.set(cacheKey, permissionMap);
|
|
716
|
+
return permissionMap;
|
|
717
|
+
}
|
|
718
|
+
/**
|
|
719
|
+
* Check if user is super admin
|
|
720
|
+
*
|
|
721
|
+
* @param userId - User ID
|
|
722
|
+
* @returns Promise resolving to super admin status
|
|
723
|
+
*/
|
|
724
|
+
async checkSuperAdmin(userId) {
|
|
725
|
+
const cacheKey = `super_admin:${userId}`;
|
|
726
|
+
const cached = rbacCache.get(cacheKey);
|
|
727
|
+
if (cached !== null) {
|
|
728
|
+
return cached;
|
|
729
|
+
}
|
|
730
|
+
const { data, error } = await this.supabase.from("rbac_global_roles").select("id").eq("user_id", userId).eq("role", "super_admin").is("valid_to", null).single();
|
|
731
|
+
const isSuperAdmin2 = !error && !!data;
|
|
732
|
+
rbacCache.set(cacheKey, isSuperAdmin2, 6e4);
|
|
733
|
+
return isSuperAdmin2;
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Get app configuration including requires_event setting
|
|
737
|
+
*
|
|
738
|
+
* @param appId - App ID
|
|
739
|
+
* @returns Promise resolving to app configuration
|
|
740
|
+
*/
|
|
741
|
+
async getAppConfig(appId) {
|
|
742
|
+
const { data, error } = await this.supabase.from("rbac_apps").select("requires_event").eq("id", appId).eq("is_active", true).single();
|
|
743
|
+
if (error || !data) {
|
|
744
|
+
return null;
|
|
745
|
+
}
|
|
746
|
+
return { requires_event: data.requires_event };
|
|
747
|
+
}
|
|
748
|
+
/**
|
|
749
|
+
* Resolve organisation ID from event ID
|
|
750
|
+
*
|
|
751
|
+
* @param eventId - Event ID
|
|
752
|
+
* @returns Promise resolving to organisation ID
|
|
753
|
+
*/
|
|
754
|
+
async resolveOrganisationFromEvent(eventId) {
|
|
755
|
+
const { data, error } = await this.supabase.from("event").select("organisation_id").eq("id", eventId).single();
|
|
756
|
+
if (error || !data) {
|
|
757
|
+
return null;
|
|
758
|
+
}
|
|
759
|
+
return data.organisation_id;
|
|
760
|
+
}
|
|
761
|
+
/**
|
|
762
|
+
* Validate context requirements based on app configuration
|
|
763
|
+
*
|
|
764
|
+
* @param scope - Permission scope
|
|
765
|
+
* @param appId - Optional app ID
|
|
766
|
+
* @returns Promise resolving to validated scope with resolved organisation ID
|
|
767
|
+
*/
|
|
768
|
+
async validateContextRequirements(scope, appId) {
|
|
769
|
+
if (appId) {
|
|
770
|
+
const appConfig = await this.getAppConfig(appId);
|
|
771
|
+
if (!appConfig) {
|
|
772
|
+
return null;
|
|
773
|
+
}
|
|
774
|
+
if (appConfig.requires_event) {
|
|
775
|
+
if (!scope.eventId) {
|
|
776
|
+
return null;
|
|
777
|
+
}
|
|
778
|
+
if (!scope.organisationId) {
|
|
779
|
+
const resolvedOrgId = await this.resolveOrganisationFromEvent(scope.eventId);
|
|
780
|
+
if (!resolvedOrgId) {
|
|
781
|
+
return null;
|
|
782
|
+
}
|
|
783
|
+
return {
|
|
784
|
+
...scope,
|
|
785
|
+
organisationId: resolvedOrgId
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
return scope;
|
|
789
|
+
} else {
|
|
790
|
+
if (!scope.organisationId) {
|
|
791
|
+
return null;
|
|
792
|
+
}
|
|
793
|
+
return scope;
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
if (!scope.organisationId) {
|
|
797
|
+
return null;
|
|
798
|
+
}
|
|
799
|
+
return scope;
|
|
800
|
+
}
|
|
801
|
+
/**
|
|
802
|
+
* Collect active grants for a user in a scope
|
|
803
|
+
*
|
|
804
|
+
* @param userId - User ID
|
|
805
|
+
* @param scope - Permission scope
|
|
806
|
+
* @param pageId - Optional page ID
|
|
807
|
+
* @returns Promise resolving to grants array
|
|
808
|
+
*
|
|
809
|
+
* PRECEDENCE ORDER (closest scope first): page → eventApp → organisation → global
|
|
810
|
+
*/
|
|
811
|
+
async collectActiveGrants(userId, scope, pageId) {
|
|
812
|
+
const grants = [];
|
|
813
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
814
|
+
const userRoles = [];
|
|
815
|
+
if (scope.eventId && scope.appId) {
|
|
816
|
+
const { data: eventRoles } = await this.supabase.from("rbac_event_app_roles").select("role, status, valid_from, valid_to").eq("user_id", userId).eq("event_id", scope.eventId).eq("app_id", scope.appId).eq("status", "active").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`);
|
|
817
|
+
if (eventRoles) {
|
|
818
|
+
userRoles.push(...eventRoles.map((r) => r.role));
|
|
819
|
+
for (const role of eventRoles) {
|
|
820
|
+
grants.push({
|
|
821
|
+
type: "allow",
|
|
822
|
+
permission: this.getPermissionForEventRole(role.role),
|
|
823
|
+
scope: "eventApp",
|
|
824
|
+
source: "rbac_event_app_roles"
|
|
825
|
+
});
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
if (scope.organisationId) {
|
|
830
|
+
const { data: orgRoles } = await this.supabase.from("rbac_organisation_roles").select("role, status, valid_from, valid_to").eq("user_id", userId).eq("organisation_id", scope.organisationId).eq("status", "active").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`);
|
|
831
|
+
if (orgRoles) {
|
|
832
|
+
userRoles.push(...orgRoles.map((r) => r.role));
|
|
833
|
+
for (const role of orgRoles) {
|
|
834
|
+
grants.push({
|
|
835
|
+
type: "allow",
|
|
836
|
+
permission: this.getPermissionForOrgRole(role.role),
|
|
837
|
+
scope: "organisation",
|
|
838
|
+
source: "rbac_organisation_roles"
|
|
839
|
+
});
|
|
840
|
+
}
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
console.log("[collectActiveGrants] User roles:", userRoles);
|
|
844
|
+
if (pageId) {
|
|
845
|
+
let resolvedPageId = null;
|
|
846
|
+
if (typeof pageId === "string") {
|
|
847
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
848
|
+
if (uuidRegex.test(pageId)) {
|
|
849
|
+
resolvedPageId = pageId;
|
|
850
|
+
} else {
|
|
851
|
+
const appId = scope.appId;
|
|
852
|
+
if (appId) {
|
|
853
|
+
const { data: page } = await this.supabase.from("rbac_app_pages").select("id").eq("app_id", appId).eq("page_name", pageId).single();
|
|
854
|
+
resolvedPageId = page?.id || null;
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
} else {
|
|
858
|
+
resolvedPageId = pageId;
|
|
859
|
+
}
|
|
860
|
+
if (resolvedPageId && scope.appId) {
|
|
861
|
+
console.log("[collectActiveGrants] Fetching page permissions via RPC for page:", resolvedPageId);
|
|
862
|
+
let pageName = null;
|
|
863
|
+
if (typeof pageId === "string" && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(pageId)) {
|
|
864
|
+
pageName = pageId;
|
|
865
|
+
} else {
|
|
866
|
+
const { data: page } = await this.supabase.from("rbac_app_pages").select("page_name").eq("id", resolvedPageId).single();
|
|
867
|
+
pageName = page?.page_name || null;
|
|
868
|
+
}
|
|
869
|
+
const rpcResult = await this.supabase.rpc("get_rbac_permissions", {
|
|
870
|
+
p_user_id: userId,
|
|
871
|
+
p_app_id: scope.appId,
|
|
872
|
+
p_event_id: scope.eventId || null,
|
|
873
|
+
p_organisation_id: scope.organisationId || null,
|
|
874
|
+
p_page_id: resolvedPageId
|
|
875
|
+
});
|
|
876
|
+
const { data: rpcPermissions } = rpcResult;
|
|
877
|
+
console.log("[collectActiveGrants] RPC page permissions:", rpcPermissions);
|
|
878
|
+
if (rpcPermissions && pageName) {
|
|
879
|
+
const pagePerms = rpcPermissions.filter(
|
|
880
|
+
(p) => p.permission_type !== "all_permissions" && p.permission_type !== "organisation_access" && p.permission_type !== "event_app_access"
|
|
881
|
+
);
|
|
882
|
+
for (const perm of pagePerms) {
|
|
883
|
+
if (userRoles.includes(perm.role_name)) {
|
|
884
|
+
console.log("[collectActiveGrants] Adding page grant:", { operation: perm.permission_type, role: perm.role_name, allowed: perm.has_permission, pageName });
|
|
885
|
+
grants.push({
|
|
886
|
+
type: perm.has_permission ? "allow" : "deny",
|
|
887
|
+
// Use page.${pageName} format for specific page permissions
|
|
888
|
+
permission: `${perm.permission_type}:page.${pageName}`,
|
|
889
|
+
scope: "page",
|
|
890
|
+
source: "rbac_page_permissions"
|
|
891
|
+
});
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
}
|
|
896
|
+
}
|
|
897
|
+
const { data: globalRoles } = await this.supabase.from("rbac_global_roles").select("role, valid_from, valid_to").eq("user_id", userId).lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`);
|
|
898
|
+
if (globalRoles) {
|
|
899
|
+
for (const role of globalRoles) {
|
|
900
|
+
if (role.role === "super_admin") {
|
|
901
|
+
grants.push({
|
|
902
|
+
type: "allow",
|
|
903
|
+
permission: "manage:*",
|
|
904
|
+
scope: "global",
|
|
905
|
+
source: "rbac_global_roles"
|
|
906
|
+
});
|
|
907
|
+
}
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
console.log("[collectActiveGrants] Final grants:", grants);
|
|
911
|
+
return grants;
|
|
912
|
+
}
|
|
913
|
+
/**
|
|
914
|
+
* Check page-specific permissions
|
|
915
|
+
*
|
|
916
|
+
* @param userId - User ID
|
|
917
|
+
* @param pageId - Page ID
|
|
918
|
+
* @param permission - Permission to check
|
|
919
|
+
* @param scope - Permission scope
|
|
920
|
+
* @returns Promise resolving to page permission result
|
|
921
|
+
*/
|
|
922
|
+
async checkPagePermissions(userId, pageId, permission, scope) {
|
|
923
|
+
if (!pageId) {
|
|
924
|
+
return true;
|
|
925
|
+
}
|
|
926
|
+
const [operation] = permission.split(":");
|
|
927
|
+
const userRoles = [];
|
|
928
|
+
if (scope.organisationId) {
|
|
929
|
+
const orgRole = await this.getOrganisationRole(userId, scope.organisationId);
|
|
930
|
+
if (orgRole) {
|
|
931
|
+
userRoles.push(orgRole);
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
if (scope.eventId && scope.appId) {
|
|
935
|
+
const eventRole = await this.getEventAppRole(userId, scope.eventId, scope.appId);
|
|
936
|
+
if (eventRole) {
|
|
937
|
+
userRoles.push(eventRole);
|
|
938
|
+
}
|
|
939
|
+
}
|
|
940
|
+
let resolvedPageId = null;
|
|
941
|
+
if (typeof pageId === "string") {
|
|
942
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
943
|
+
if (uuidRegex.test(pageId)) {
|
|
944
|
+
resolvedPageId = pageId;
|
|
945
|
+
} else {
|
|
946
|
+
let appId = scope.appId;
|
|
947
|
+
if (!appId) {
|
|
948
|
+
const appName = process.env.VITE_APP_NAME || process.env.REACT_APP_NAME;
|
|
949
|
+
if (appName) {
|
|
950
|
+
const { data: app } = await this.supabase.from("rbac_apps").select("id").eq("name", appName).eq("is_active", true).single();
|
|
951
|
+
if (app) {
|
|
952
|
+
appId = app.id;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
}
|
|
956
|
+
if (appId) {
|
|
957
|
+
const { data: page } = await this.supabase.from("rbac_app_pages").select("id").eq("app_id", appId).eq("page_name", pageId).single();
|
|
958
|
+
resolvedPageId = page?.id || null;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
} else {
|
|
962
|
+
resolvedPageId = pageId;
|
|
963
|
+
}
|
|
964
|
+
if (!resolvedPageId) {
|
|
965
|
+
return false;
|
|
966
|
+
}
|
|
967
|
+
const { data: pagePermissions } = await this.supabase.from("rbac_page_permissions").select("allowed").eq("app_page_id", resolvedPageId).eq("operation", operation).in("role_name", userRoles).single();
|
|
968
|
+
return pagePermissions?.allowed ?? false;
|
|
969
|
+
}
|
|
970
|
+
/**
|
|
971
|
+
* Get organisation role for a user
|
|
972
|
+
*
|
|
973
|
+
* @param userId - User ID
|
|
974
|
+
* @param organisationId - Organisation ID
|
|
975
|
+
* @returns Promise resolving to organisation role
|
|
976
|
+
*/
|
|
977
|
+
async getOrganisationRole(userId, organisationId) {
|
|
978
|
+
const { data, error } = await this.supabase.from("rbac_organisation_roles").select("role").eq("user_id", userId).eq("organisation_id", organisationId).eq("status", "active").single();
|
|
979
|
+
return error ? null : data?.role || null;
|
|
980
|
+
}
|
|
981
|
+
/**
|
|
982
|
+
* Get event-app role for a user
|
|
983
|
+
*
|
|
984
|
+
* @param userId - User ID
|
|
985
|
+
* @param eventId - Event ID
|
|
986
|
+
* @param appId - App ID
|
|
987
|
+
* @returns Promise resolving to event-app role
|
|
988
|
+
*/
|
|
989
|
+
async getEventAppRole(userId, eventId, appId) {
|
|
990
|
+
const { data, error } = await this.supabase.from("rbac_event_app_roles").select("role, status, valid_from, valid_to").eq("user_id", userId).eq("event_id", eventId).eq("app_id", appId).eq("status", "active").lte("valid_from", (/* @__PURE__ */ new Date()).toISOString()).or(`valid_to.is.null,valid_to.gte.${(/* @__PURE__ */ new Date()).toISOString()}`).single();
|
|
991
|
+
return error ? null : data?.role || null;
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Get permission for organisation role
|
|
995
|
+
*
|
|
996
|
+
* @param role - Organisation role
|
|
997
|
+
* @returns Permission string
|
|
998
|
+
*/
|
|
999
|
+
getPermissionForOrgRole(role) {
|
|
1000
|
+
switch (role) {
|
|
1001
|
+
case "org_admin":
|
|
1002
|
+
return "manage:*";
|
|
1003
|
+
case "leader":
|
|
1004
|
+
return "manage:organisation.*";
|
|
1005
|
+
case "member":
|
|
1006
|
+
return "read:organisation.*";
|
|
1007
|
+
case "supporter":
|
|
1008
|
+
return "read:organisation.public";
|
|
1009
|
+
default:
|
|
1010
|
+
return "read:organisation.public";
|
|
1011
|
+
}
|
|
1012
|
+
}
|
|
1013
|
+
/**
|
|
1014
|
+
* Get permission for event-app role
|
|
1015
|
+
*
|
|
1016
|
+
* @param role - Event-app role
|
|
1017
|
+
* @returns Permission string
|
|
1018
|
+
*/
|
|
1019
|
+
getPermissionForEventRole(role) {
|
|
1020
|
+
switch (role) {
|
|
1021
|
+
case "event_admin":
|
|
1022
|
+
return "manage:event.*";
|
|
1023
|
+
case "planner":
|
|
1024
|
+
return "manage:event.planning";
|
|
1025
|
+
case "participant":
|
|
1026
|
+
return "read:event.*";
|
|
1027
|
+
case "viewer":
|
|
1028
|
+
return "read:event.public";
|
|
1029
|
+
default:
|
|
1030
|
+
return "read:event.public";
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
/**
|
|
1034
|
+
* Check if a permission matches another permission
|
|
1035
|
+
*
|
|
1036
|
+
* @param grantPermission - Permission from grant
|
|
1037
|
+
* @param requestedPermission - Requested permission
|
|
1038
|
+
* @returns True if permissions match
|
|
1039
|
+
*/
|
|
1040
|
+
permissionMatches(grantPermission, requestedPermission) {
|
|
1041
|
+
console.log("[permissionMatches] Checking:", { grantPermission, requestedPermission });
|
|
1042
|
+
if (grantPermission === requestedPermission) {
|
|
1043
|
+
console.log("[permissionMatches] Exact match found");
|
|
1044
|
+
return true;
|
|
1045
|
+
}
|
|
1046
|
+
if (grantPermission.endsWith(":*") || grantPermission.endsWith(".*")) {
|
|
1047
|
+
const [grantOp, grantResource] = grantPermission.split(":");
|
|
1048
|
+
const [requestedOp, requestedResource] = requestedPermission.split(":");
|
|
1049
|
+
console.log("[permissionMatches] Wildcard check:", {
|
|
1050
|
+
grantOp,
|
|
1051
|
+
grantResource,
|
|
1052
|
+
requestedOp,
|
|
1053
|
+
requestedResource,
|
|
1054
|
+
operationsMatch: grantOp === requestedOp
|
|
1055
|
+
});
|
|
1056
|
+
if (grantOp === requestedOp) {
|
|
1057
|
+
const prefix = grantResource.slice(0, -1);
|
|
1058
|
+
const matches = prefix === "" || requestedResource.startsWith(prefix);
|
|
1059
|
+
console.log("[permissionMatches] Wildcard match result:", { prefix, matches });
|
|
1060
|
+
return matches;
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
1063
|
+
if (grantPermission.includes("*")) {
|
|
1064
|
+
const [grantOp, grantResource] = grantPermission.split(":");
|
|
1065
|
+
const [requestedOp, requestedResource] = requestedPermission.split(":");
|
|
1066
|
+
console.log("[permissionMatches] Other wildcard check:", {
|
|
1067
|
+
grantOp,
|
|
1068
|
+
grantResource,
|
|
1069
|
+
requestedOp,
|
|
1070
|
+
requestedResource,
|
|
1071
|
+
operationsMatch: grantOp === requestedOp
|
|
1072
|
+
});
|
|
1073
|
+
if (grantOp === requestedOp) {
|
|
1074
|
+
const prefix = grantResource.replace("*", "");
|
|
1075
|
+
const matches = requestedResource.startsWith(prefix);
|
|
1076
|
+
console.log("[permissionMatches] Other wildcard match result:", { prefix, matches });
|
|
1077
|
+
return matches;
|
|
1078
|
+
}
|
|
1079
|
+
}
|
|
1080
|
+
console.log("[permissionMatches] No match found");
|
|
1081
|
+
return false;
|
|
1082
|
+
}
|
|
1083
|
+
/**
|
|
1084
|
+
* Resolve a page ID to UUID if it's a page name
|
|
1085
|
+
*
|
|
1086
|
+
* @param pageId - Page ID (UUID) or page name (string)
|
|
1087
|
+
* @param appId - App ID to look up the page
|
|
1088
|
+
* @returns Resolved page ID (UUID) or original pageId if it's already a UUID or can't be resolved
|
|
1089
|
+
*/
|
|
1090
|
+
async resolvePageId(pageId, appId) {
|
|
1091
|
+
if (!pageId) {
|
|
1092
|
+
return void 0;
|
|
1093
|
+
}
|
|
1094
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
1095
|
+
if (uuidRegex.test(pageId)) {
|
|
1096
|
+
return pageId;
|
|
1097
|
+
}
|
|
1098
|
+
if (!appId) {
|
|
1099
|
+
return pageId;
|
|
1100
|
+
}
|
|
1101
|
+
try {
|
|
1102
|
+
const { data: page } = await this.supabase.from("rbac_app_pages").select("id").eq("app_id", appId).eq("page_name", pageId).single();
|
|
1103
|
+
return page?.id || pageId;
|
|
1104
|
+
} catch (error) {
|
|
1105
|
+
console.warn("[RBAC Engine] Failed to resolve page name to UUID:", { pageId, appId, error });
|
|
1106
|
+
return pageId;
|
|
1107
|
+
}
|
|
1108
|
+
}
|
|
1109
|
+
};
|
|
1110
|
+
function createRBACEngine(supabase) {
|
|
1111
|
+
return new RBACEngine(supabase);
|
|
1112
|
+
}
|
|
1113
|
+
|
|
1114
|
+
// src/rbac/config.ts
|
|
1115
|
+
var RBACConfigManager = class {
|
|
1116
|
+
constructor() {
|
|
1117
|
+
this.config = null;
|
|
1118
|
+
this.logger = null;
|
|
1119
|
+
}
|
|
1120
|
+
setConfig(config) {
|
|
1121
|
+
this.config = config;
|
|
1122
|
+
this.setupLogger();
|
|
1123
|
+
}
|
|
1124
|
+
getConfig() {
|
|
1125
|
+
return this.config;
|
|
1126
|
+
}
|
|
1127
|
+
getLogger() {
|
|
1128
|
+
if (!this.logger) {
|
|
1129
|
+
this.logger = this.createDefaultLogger();
|
|
1130
|
+
}
|
|
1131
|
+
return this.logger;
|
|
1132
|
+
}
|
|
1133
|
+
setupLogger() {
|
|
1134
|
+
if (!this.config) return;
|
|
1135
|
+
const { debug = false, logLevel = "warn" } = this.config;
|
|
1136
|
+
this.logger = {
|
|
1137
|
+
error: (message, ...args) => {
|
|
1138
|
+
console.error(`[RBAC ERROR] ${message}`, ...args);
|
|
1139
|
+
},
|
|
1140
|
+
warn: (message, ...args) => {
|
|
1141
|
+
if (logLevel === "warn" || logLevel === "info" || logLevel === "debug") {
|
|
1142
|
+
console.warn(`[RBAC WARN] ${message}`, ...args);
|
|
1143
|
+
}
|
|
1144
|
+
},
|
|
1145
|
+
info: (message, ...args) => {
|
|
1146
|
+
if (logLevel === "info" || logLevel === "debug") {
|
|
1147
|
+
console.info(`[RBAC INFO] ${message}`, ...args);
|
|
1148
|
+
}
|
|
1149
|
+
},
|
|
1150
|
+
debug: (message, ...args) => {
|
|
1151
|
+
if (debug && logLevel === "debug") {
|
|
1152
|
+
console.debug(`[RBAC DEBUG] ${message}`, ...args);
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
}
|
|
1157
|
+
createDefaultLogger() {
|
|
1158
|
+
return {
|
|
1159
|
+
error: (message, ...args) => console.error(`[RBAC ERROR] ${message}`, ...args),
|
|
1160
|
+
warn: (message, ...args) => console.warn(`[RBAC WARN] ${message}`, ...args),
|
|
1161
|
+
info: (message, ...args) => console.info(`[RBAC INFO] ${message}`, ...args),
|
|
1162
|
+
debug: (message, ...args) => console.debug(`[RBAC DEBUG] ${message}`, ...args)
|
|
1163
|
+
};
|
|
1164
|
+
}
|
|
1165
|
+
isDebugMode() {
|
|
1166
|
+
return this.config?.debug ?? false;
|
|
1167
|
+
}
|
|
1168
|
+
isDevelopmentMode() {
|
|
1169
|
+
return this.config?.developmentMode ?? false;
|
|
1170
|
+
}
|
|
1171
|
+
getMockPermissions() {
|
|
1172
|
+
return this.config?.mockPermissions ?? null;
|
|
1173
|
+
}
|
|
1174
|
+
};
|
|
1175
|
+
var configManager = new RBACConfigManager();
|
|
1176
|
+
function createRBACConfig(config) {
|
|
1177
|
+
configManager.setConfig(config);
|
|
1178
|
+
return config;
|
|
1179
|
+
}
|
|
1180
|
+
function getRBACConfig() {
|
|
1181
|
+
return configManager.getConfig();
|
|
1182
|
+
}
|
|
1183
|
+
function getRBACLogger() {
|
|
1184
|
+
return configManager.getLogger();
|
|
1185
|
+
}
|
|
1186
|
+
function isDebugMode() {
|
|
1187
|
+
return configManager.isDebugMode();
|
|
1188
|
+
}
|
|
1189
|
+
function isDevelopmentMode() {
|
|
1190
|
+
return configManager.isDevelopmentMode();
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
// src/rbac/api.ts
|
|
1194
|
+
var globalEngine = null;
|
|
1195
|
+
function setupRBAC(supabase, config) {
|
|
1196
|
+
const logger = getRBACLogger();
|
|
1197
|
+
const fullConfig = {
|
|
1198
|
+
supabase,
|
|
1199
|
+
debug: false,
|
|
1200
|
+
logLevel: "warn",
|
|
1201
|
+
developmentMode: false,
|
|
1202
|
+
...config
|
|
1203
|
+
};
|
|
1204
|
+
createRBACConfig(fullConfig);
|
|
1205
|
+
globalEngine = createRBACEngine(supabase);
|
|
1206
|
+
const auditManager = createAuditManager(supabase);
|
|
1207
|
+
setGlobalAuditManager(auditManager);
|
|
1208
|
+
logger.info("RBAC system initialized successfully");
|
|
1209
|
+
}
|
|
1210
|
+
function getEngine() {
|
|
1211
|
+
if (!globalEngine) {
|
|
1212
|
+
throw new RBACNotInitializedError();
|
|
1213
|
+
}
|
|
1214
|
+
return globalEngine;
|
|
1215
|
+
}
|
|
1216
|
+
async function getAccessLevel(input) {
|
|
1217
|
+
const engine = getEngine();
|
|
1218
|
+
return engine.getAccessLevel(input);
|
|
1219
|
+
}
|
|
1220
|
+
async function getPermissionMap(input) {
|
|
1221
|
+
const engine = getEngine();
|
|
1222
|
+
return engine.getPermissionMap(input);
|
|
1223
|
+
}
|
|
1224
|
+
async function isPermitted(input) {
|
|
1225
|
+
const engine = getEngine();
|
|
1226
|
+
return engine.isPermitted(input);
|
|
1227
|
+
}
|
|
1228
|
+
async function isPermittedCached(input) {
|
|
1229
|
+
const { userId, scope, permission, pageId } = input;
|
|
1230
|
+
const cacheKey = RBACCache.generatePermissionKey({
|
|
1231
|
+
userId,
|
|
1232
|
+
organisationId: scope.organisationId,
|
|
1233
|
+
eventId: scope.eventId,
|
|
1234
|
+
appId: scope.appId
|
|
1235
|
+
});
|
|
1236
|
+
const cached = rbacCache.get(cacheKey);
|
|
1237
|
+
if (cached !== null) {
|
|
1238
|
+
return cached;
|
|
1239
|
+
}
|
|
1240
|
+
const result = await isPermitted(input);
|
|
1241
|
+
rbacCache.set(cacheKey, result);
|
|
1242
|
+
return result;
|
|
1243
|
+
}
|
|
1244
|
+
async function hasPermission(input) {
|
|
1245
|
+
return isPermitted(input);
|
|
1246
|
+
}
|
|
1247
|
+
async function hasAnyPermission(input) {
|
|
1248
|
+
const { permissions, ...baseInput } = input;
|
|
1249
|
+
for (const permission of permissions) {
|
|
1250
|
+
const hasPermission2 = await isPermitted({
|
|
1251
|
+
...baseInput,
|
|
1252
|
+
permission
|
|
1253
|
+
});
|
|
1254
|
+
if (hasPermission2) {
|
|
1255
|
+
return true;
|
|
1256
|
+
}
|
|
1257
|
+
}
|
|
1258
|
+
return false;
|
|
1259
|
+
}
|
|
1260
|
+
async function hasAllPermissions(input) {
|
|
1261
|
+
const { permissions, ...baseInput } = input;
|
|
1262
|
+
for (const permission of permissions) {
|
|
1263
|
+
const hasPermission2 = await isPermitted({
|
|
1264
|
+
...baseInput,
|
|
1265
|
+
permission
|
|
1266
|
+
});
|
|
1267
|
+
if (!hasPermission2) {
|
|
1268
|
+
return false;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
return true;
|
|
1272
|
+
}
|
|
1273
|
+
async function isSuperAdmin(userId) {
|
|
1274
|
+
const engine = getEngine();
|
|
1275
|
+
return engine["checkSuperAdmin"](userId);
|
|
1276
|
+
}
|
|
1277
|
+
async function getAppConfig(appId) {
|
|
1278
|
+
const engine = getEngine();
|
|
1279
|
+
return engine["getAppConfig"](appId);
|
|
1280
|
+
}
|
|
1281
|
+
async function isOrganisationAdmin(userId, organisationId) {
|
|
1282
|
+
const accessLevel = await getAccessLevel({
|
|
1283
|
+
userId,
|
|
1284
|
+
scope: { organisationId }
|
|
1285
|
+
});
|
|
1286
|
+
return accessLevel === "admin" || accessLevel === "super";
|
|
1287
|
+
}
|
|
1288
|
+
async function isEventAdmin(userId, scope) {
|
|
1289
|
+
if (!scope.eventId || !scope.appId) {
|
|
1290
|
+
return false;
|
|
1291
|
+
}
|
|
1292
|
+
const accessLevel = await getAccessLevel({ userId, scope });
|
|
1293
|
+
return accessLevel === "admin" || accessLevel === "super";
|
|
1294
|
+
}
|
|
1295
|
+
function invalidateUserCache(userId, organisationId) {
|
|
1296
|
+
if (organisationId) {
|
|
1297
|
+
rbacCache.invalidate(CACHE_PATTERNS.PERMISSION(userId, organisationId));
|
|
1298
|
+
} else {
|
|
1299
|
+
rbacCache.invalidate(CACHE_PATTERNS.USER(userId));
|
|
1300
|
+
}
|
|
1301
|
+
}
|
|
1302
|
+
function invalidateOrganisationCache(organisationId) {
|
|
1303
|
+
rbacCache.invalidate(CACHE_PATTERNS.ORGANISATION(organisationId));
|
|
1304
|
+
}
|
|
1305
|
+
function invalidateEventCache(eventId) {
|
|
1306
|
+
rbacCache.invalidate(CACHE_PATTERNS.EVENT(eventId));
|
|
1307
|
+
}
|
|
1308
|
+
function invalidateAppCache(appId) {
|
|
1309
|
+
rbacCache.invalidate(CACHE_PATTERNS.APP(appId));
|
|
1310
|
+
}
|
|
1311
|
+
function clearCache() {
|
|
1312
|
+
rbacCache.clear();
|
|
1313
|
+
}
|
|
1314
|
+
|
|
1315
|
+
export {
|
|
1316
|
+
OrganisationContextRequiredError,
|
|
1317
|
+
RBACCache,
|
|
1318
|
+
rbacCache,
|
|
1319
|
+
CACHE_PATTERNS,
|
|
1320
|
+
RBACEngine,
|
|
1321
|
+
createRBACEngine,
|
|
1322
|
+
createRBACConfig,
|
|
1323
|
+
getRBACConfig,
|
|
1324
|
+
getRBACLogger,
|
|
1325
|
+
isDebugMode,
|
|
1326
|
+
isDevelopmentMode,
|
|
1327
|
+
setupRBAC,
|
|
1328
|
+
getAccessLevel,
|
|
1329
|
+
getPermissionMap,
|
|
1330
|
+
isPermitted,
|
|
1331
|
+
isPermittedCached,
|
|
1332
|
+
hasPermission,
|
|
1333
|
+
hasAnyPermission,
|
|
1334
|
+
hasAllPermissions,
|
|
1335
|
+
isSuperAdmin,
|
|
1336
|
+
getAppConfig,
|
|
1337
|
+
isOrganisationAdmin,
|
|
1338
|
+
isEventAdmin,
|
|
1339
|
+
invalidateUserCache,
|
|
1340
|
+
invalidateOrganisationCache,
|
|
1341
|
+
invalidateEventCache,
|
|
1342
|
+
invalidateAppCache,
|
|
1343
|
+
clearCache
|
|
1344
|
+
};
|
|
1345
|
+
//# sourceMappingURL=chunk-6ZQVSHKL.js.map
|