@jmruthers/pace-core 0.6.5 → 0.6.7
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 +104 -0
- package/README.md +5 -403
- package/audit-tool/00-dependencies.cjs +394 -0
- package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
- package/audit-tool/audits/02-project-structure.cjs +255 -0
- package/audit-tool/audits/03-architecture.cjs +196 -0
- package/audit-tool/audits/04-code-quality.cjs +149 -0
- package/audit-tool/audits/05-styling.cjs +224 -0
- package/audit-tool/audits/06-security-rbac.cjs +544 -0
- package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
- package/audit-tool/audits/08-testing-documentation.cjs +202 -0
- package/audit-tool/audits/09-operations.cjs +208 -0
- package/audit-tool/index.cjs +291 -0
- package/audit-tool/utils/code-utils.cjs +218 -0
- package/audit-tool/utils/file-utils.cjs +230 -0
- package/audit-tool/utils/report-utils.cjs +241 -0
- package/core-usage-manifest.json +93 -0
- package/cursor-rules/00-standards-overview.mdc +156 -0
- package/cursor-rules/01-pace-core-compliance.mdc +586 -0
- package/cursor-rules/02-project-structure.mdc +42 -4
- package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
- package/cursor-rules/04-code-quality.mdc +419 -0
- package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
- package/cursor-rules/06-security-rbac.mdc +518 -0
- package/cursor-rules/07-api-tech-stack.mdc +377 -0
- package/cursor-rules/08-testing-documentation.mdc +324 -0
- package/cursor-rules/09-operations.mdc +365 -0
- package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
- package/dist/DataTable-7PMH7XN7.js +15 -0
- package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
- package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
- package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
- package/dist/api-Y4MQWOFW.js +4 -0
- package/dist/audit-MYQXYZFU.js +3 -0
- package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
- package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
- package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
- package/dist/chunk-6F3IILHI.js +62 -0
- package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
- package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
- package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
- package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
- package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
- package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
- package/dist/chunk-C7NSAPTL.js +1 -0
- package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
- package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
- package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
- package/dist/chunk-GHYHJTYV.js +994 -0
- package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
- package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
- package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
- package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
- package/dist/chunk-MBADTM7L.js +64 -0
- package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
- package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
- package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
- package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
- package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
- package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
- package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
- package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
- package/dist/components.d.ts +7 -5
- package/dist/components.js +46 -257
- package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
- package/dist/eslint-rules/index.cjs +35 -0
- package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
- package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
- package/dist/eslint-rules/rules/05-styling.cjs +61 -0
- package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
- package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
- package/dist/eslint-rules/rules/08-testing.cjs +94 -0
- package/dist/eslint-rules/utils/helpers.cjs +42 -0
- package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
- package/dist/hooks.d.ts +6 -6
- package/dist/hooks.js +62 -172
- package/dist/icons/index.d.ts +1 -0
- package/dist/icons/index.js +1 -0
- package/dist/index.d.ts +12 -11
- package/dist/index.js +67 -660
- package/dist/providers.d.ts +2 -2
- package/dist/providers.js +8 -35
- package/dist/rbac/eslint-rules.d.ts +46 -44
- package/dist/rbac/eslint-rules.js +7 -4
- package/dist/rbac/index.d.ts +109 -586
- package/dist/rbac/index.js +14 -207
- package/dist/styles/index.js +2 -12
- package/dist/theming/runtime.d.ts +14 -1
- package/dist/theming/runtime.js +3 -19
- package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
- package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
- package/dist/types-t9H8qKRw.d.ts +55 -0
- package/dist/types.d.ts +1 -1
- package/dist/types.js +7 -94
- package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
- package/dist/utils.d.ts +24 -117
- package/dist/utils.js +54 -392
- package/docs/README.md +17 -7
- package/docs/api/README.md +4 -402
- package/docs/api/modules.md +301 -871
- package/docs/api-reference/components.md +21 -21
- package/docs/api-reference/deprecated.md +31 -6
- package/docs/api-reference/hooks.md +80 -80
- package/docs/api-reference/rpc-functions.md +78 -3
- package/docs/api-reference/types.md +1 -1
- package/docs/api-reference/utilities.md +1 -1
- package/docs/architecture/README.md +1 -1
- package/docs/core-concepts/events.md +3 -3
- package/docs/core-concepts/organisations.md +6 -6
- package/docs/core-concepts/permissions.md +6 -6
- package/docs/documentation-index.md +12 -18
- package/docs/getting-started/cursor-rules.md +3 -23
- package/docs/getting-started/dependencies.md +650 -0
- package/docs/getting-started/documentation-index.md +1 -1
- package/docs/getting-started/examples/README.md +4 -4
- package/docs/getting-started/examples/full-featured-app.md +1 -1
- package/docs/getting-started/faq.md +2 -2
- package/docs/getting-started/installation-guide.md +20 -7
- package/docs/getting-started/quick-reference.md +4 -4
- package/docs/getting-started/quick-start.md +23 -12
- package/docs/implementation-guides/authentication.md +15 -15
- package/docs/implementation-guides/component-styling.md +1 -1
- package/docs/implementation-guides/data-tables.md +126 -33
- package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
- package/docs/implementation-guides/dynamic-colors.md +3 -3
- package/docs/implementation-guides/file-upload-storage.md +2 -2
- package/docs/implementation-guides/hierarchical-datatable.md +40 -60
- package/docs/implementation-guides/inactivity-tracking.md +3 -3
- package/docs/implementation-guides/large-datasets.md +3 -2
- package/docs/implementation-guides/organisation-security.md +2 -2
- package/docs/implementation-guides/performance.md +2 -2
- package/docs/implementation-guides/permission-enforcement.md +5 -1
- package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
- package/docs/migration/V0.4.0_rbac-migration.md +6 -6
- package/docs/rbac/MIGRATION_GUIDE.md +819 -0
- package/docs/rbac/RBAC_CONTRACT.md +724 -0
- package/docs/rbac/README.md +17 -8
- package/docs/rbac/advanced-patterns.md +6 -6
- package/docs/rbac/api-reference.md +20 -20
- package/docs/rbac/edge-functions-guide.md +376 -0
- package/docs/rbac/event-based-apps.md +3 -3
- package/docs/rbac/examples.md +41 -41
- package/docs/rbac/getting-started.md +37 -37
- package/docs/rbac/performance.md +1 -1
- package/docs/rbac/quick-start.md +52 -52
- package/docs/rbac/secure-client-protection.md +1 -35
- package/docs/rbac/troubleshooting.md +1 -1
- package/docs/security/README.md +5 -5
- package/docs/standards/0-standards-overview.md +220 -0
- package/docs/standards/1-pace-core-compliance-standards.md +986 -0
- package/docs/standards/2-project-structure-standards.md +949 -0
- package/docs/standards/3-architecture-standards.md +606 -0
- package/docs/standards/4-code-quality-standards.md +728 -0
- package/docs/standards/5-styling-standards.md +348 -0
- package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
- package/docs/standards/7-api-tech-stack-standards.md +662 -0
- package/docs/standards/8-testing-documentation-standards.md +401 -0
- package/docs/standards/9-operations-standards.md +1102 -0
- package/docs/standards/README.md +185 -57
- package/docs/troubleshooting/README.md +4 -4
- package/docs/troubleshooting/common-issues.md +2 -2
- package/docs/troubleshooting/debugging.md +9 -9
- package/docs/troubleshooting/migration.md +4 -4
- package/docs/troubleshooting/organisation-context-setup.md +42 -19
- package/eslint-config-pace-core.cjs +33 -6
- package/package.json +35 -23
- package/scripts/install-cursor-rules.cjs +25 -6
- package/scripts/install-eslint-config.cjs +284 -0
- package/src/__tests__/fixtures/supabase.ts +1 -1
- package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
- package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
- package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
- package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
- package/src/__tests__/helpers/component-test-utils.tsx +1 -1
- package/src/__tests__/helpers/supabaseMock.ts +2 -2
- package/src/__tests__/integration/UserProfile.test.tsx +14 -14
- package/src/__tests__/public-recipe-view.test.ts +38 -9
- package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
- package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
- package/src/__tests__/templates/component.test.template.tsx +18 -15
- package/src/components/Button/Button.tsx +5 -1
- package/src/components/Calendar/Calendar.tsx +201 -47
- package/src/components/ContextSelector/ContextSelector.tsx +106 -119
- package/src/components/DataTable/AUDIT_REPORT.md +293 -0
- package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
- package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
- package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
- package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
- package/src/components/DataTable/components/DataTableCore.tsx +186 -13
- package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
- package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
- package/src/components/DataTable/components/EditFields.tsx +23 -3
- package/src/components/DataTable/components/EditableRow.tsx +12 -9
- package/src/components/DataTable/components/EmptyState.tsx +10 -9
- package/src/components/DataTable/components/FilterRow.tsx +2 -4
- package/src/components/DataTable/components/ImportModal.tsx +124 -126
- package/src/components/DataTable/components/LoadingState.tsx +5 -6
- package/src/components/DataTable/components/RowComponent.tsx +12 -0
- package/src/components/DataTable/components/SortIndicator.tsx +50 -0
- package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
- package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
- package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
- package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
- package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
- package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
- package/src/components/DataTable/components/index.ts +2 -1
- package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
- package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
- package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
- package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
- package/src/components/DataTable/types.ts +5 -18
- package/src/components/DataTable/utils/a11yUtils.ts +17 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
- package/src/components/DateTimeField/DateTimeField.tsx +10 -9
- package/src/components/Dialog/Dialog.test.tsx +128 -104
- package/src/components/Dialog/Dialog.tsx +742 -24
- package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
- package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
- package/src/components/FileDisplay/FileDisplay.tsx +23 -17
- package/src/components/FileUpload/FileUpload.test.tsx +52 -14
- package/src/components/FileUpload/FileUpload.tsx +112 -130
- package/src/components/Form/Form.test.tsx +6 -8
- package/src/components/Form/Form.tsx +365 -4
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
- package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
- package/src/components/Progress/Progress.tsx +2 -4
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
- package/src/components/Select/Select.tsx +109 -98
- package/src/components/Select/types.ts +4 -1
- package/src/components/UserMenu/UserMenu.tsx +9 -6
- package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
- package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
- package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
- package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
- package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
- package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
- package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
- package/src/hooks/public/usePublicEvent.ts +67 -195
- package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
- package/src/hooks/public/usePublicEventLogo.ts +24 -14
- package/src/hooks/public/usePublicFileDisplay.ts +2 -2
- package/src/hooks/public/usePublicRouteParams.ts +5 -5
- package/src/hooks/useAppConfig.ts +28 -26
- package/src/hooks/useEventTheme.test.ts +217 -239
- package/src/hooks/useEventTheme.ts +16 -28
- package/src/hooks/useFileDisplay.ts +2 -2
- package/src/hooks/useOrganisationPermissions.ts +5 -7
- package/src/hooks/useQueryCache.ts +0 -1
- package/src/hooks/useSessionDraft.ts +380 -0
- package/src/hooks/useSessionRestoration.ts +3 -1
- package/src/icons/index.ts +27 -0
- package/src/index.ts +5 -0
- package/src/providers/OrganisationProvider.tsx +23 -14
- package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
- package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
- package/src/providers/__tests__/EventProvider.test.tsx +61 -61
- package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
- package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
- package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
- package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
- package/src/providers/services/EventServiceProvider.tsx +1 -24
- package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
- package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
- package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
- package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
- package/src/rbac/adapters.tsx +7 -295
- package/src/rbac/api.test.ts +44 -56
- package/src/rbac/api.ts +10 -17
- package/src/rbac/cache-invalidation.ts +0 -1
- package/src/rbac/compliance/index.ts +10 -0
- package/src/rbac/compliance/pattern-detector.ts +553 -0
- package/src/rbac/compliance/runtime-compliance.ts +22 -0
- package/src/rbac/components/AccessDenied.tsx +150 -0
- package/src/rbac/components/NavigationGuard.tsx +12 -20
- package/src/rbac/components/PagePermissionGuard.tsx +4 -24
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
- package/src/rbac/components/index.ts +3 -41
- package/src/rbac/eslint-rules.js +1 -1
- package/src/rbac/hooks/index.ts +0 -3
- package/src/rbac/hooks/permissions/index.ts +0 -3
- package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
- package/src/rbac/hooks/usePermissions.ts +0 -3
- package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
- package/src/rbac/hooks/useResolvedScope.ts +58 -140
- package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
- package/src/rbac/hooks/useResourcePermissions.ts +139 -48
- package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
- package/src/rbac/hooks/useRoleManagement.ts +147 -19
- package/src/rbac/hooks/useSecureSupabase.ts +4 -8
- package/src/rbac/index.ts +7 -9
- package/src/rbac/utils/contextValidator.ts +9 -7
- package/src/services/AuthService.ts +130 -18
- package/src/services/EventService.ts +4 -97
- package/src/services/InactivityService.ts +16 -0
- package/src/services/OrganisationService.ts +7 -44
- package/src/services/__tests__/OrganisationService.test.ts +26 -8
- package/src/services/base/BaseService.ts +0 -3
- package/src/styles/core.css +7 -0
- package/src/theming/__tests__/parseEventColours.test.ts +9 -3
- package/src/theming/parseEventColours.ts +22 -10
- package/src/types/database.generated.ts +4733 -3809
- package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
- package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
- package/src/utils/context/organisationContext.test.ts +13 -28
- package/src/utils/context/organisationContext.ts +21 -52
- package/src/utils/dynamic/dynamicUtils.ts +1 -1
- package/src/utils/file-reference/index.ts +39 -15
- package/src/utils/formatting/formatDateTime.test.ts +3 -2
- package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
- package/src/utils/index.ts +4 -1
- package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
- package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
- package/src/utils/persistence/keyDerivation.ts +304 -0
- package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
- package/src/utils/security/secureStorage.ts +5 -5
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.ts +3 -3
- package/src/utils/supabase/createBaseClient.ts +147 -0
- package/src/utils/timezone/timezone.test.ts +1 -2
- package/src/utils/timezone/timezone.ts +1 -1
- package/src/utils/validation/csrf.ts +4 -4
- package/cursor-rules/00-pace-core-compliance.mdc +0 -331
- package/cursor-rules/01-standards-compliance.mdc +0 -244
- package/cursor-rules/04-testing-standards.mdc +0 -268
- package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
- package/cursor-rules/06-code-quality.mdc +0 -309
- package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
- package/cursor-rules/CHANGELOG.md +0 -119
- package/cursor-rules/README.md +0 -192
- package/dist/DataTable-AOVNCPTX.js +0 -175
- package/dist/DataTable-AOVNCPTX.js.map +0 -1
- package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
- package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
- package/dist/api-O6HTBX5Y.js +0 -52
- package/dist/api-O6HTBX5Y.js.map +0 -1
- package/dist/audit-V53FV5AG.js +0 -17
- package/dist/audit-V53FV5AG.js.map +0 -1
- package/dist/chunk-5DRSZLL2.js.map +0 -1
- package/dist/chunk-63FOKYGO.js.map +0 -1
- package/dist/chunk-6COVEUS7.js.map +0 -1
- package/dist/chunk-AFVQODI2.js +0 -263
- package/dist/chunk-AFVQODI2.js.map +0 -1
- package/dist/chunk-DGUM43GV.js.map +0 -1
- package/dist/chunk-E66EQZE6.js.map +0 -1
- package/dist/chunk-EFN2EIMK.js.map +0 -1
- package/dist/chunk-FFQEQTNW.js.map +0 -1
- package/dist/chunk-FMUCXFII.js.map +0 -1
- package/dist/chunk-G37KK66H.js.map +0 -1
- package/dist/chunk-G7QEZTYQ.js +0 -2053
- package/dist/chunk-G7QEZTYQ.js.map +0 -1
- package/dist/chunk-HU2C6SSC.js.map +0 -1
- package/dist/chunk-IHB5DR3H.js.map +0 -1
- package/dist/chunk-IVOFDYWT.js.map +0 -1
- package/dist/chunk-J36DSWQK.js.map +0 -1
- package/dist/chunk-JGRYX5UX.js.map +0 -1
- package/dist/chunk-KQCRWDSA.js +0 -1
- package/dist/chunk-KQCRWDSA.js.map +0 -1
- package/dist/chunk-L4OXEN46.js.map +0 -1
- package/dist/chunk-LMC26NLJ.js +0 -84
- package/dist/chunk-LMC26NLJ.js.map +0 -1
- package/dist/chunk-M43Y4SSO.js.map +0 -1
- package/dist/chunk-M7MPQISP.js.map +0 -1
- package/dist/chunk-NTM7ZSB6.js.map +0 -1
- package/dist/chunk-PWLANIRT.js.map +0 -1
- package/dist/chunk-QXHPKYJV.js.map +0 -1
- package/dist/chunk-RGAWHO7N.js.map +0 -1
- package/dist/chunk-UPPMRMYG.js.map +0 -1
- package/dist/chunk-VBXEHIUJ.js.map +0 -1
- package/dist/chunk-ZSAAAMVR.js.map +0 -1
- package/dist/components.js.map +0 -1
- package/dist/contextValidator-5OGXSPKS.js +0 -9
- package/dist/contextValidator-5OGXSPKS.js.map +0 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
- package/dist/hooks.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/providers.js.map +0 -1
- package/dist/rbac/eslint-rules.js.map +0 -1
- package/dist/rbac/index.js.map +0 -1
- package/dist/styles/index.js.map +0 -1
- package/dist/theming/runtime.js.map +0 -1
- package/dist/types.js.map +0 -1
- package/dist/utils.js.map +0 -1
- package/docs/best-practices/README.md +0 -472
- package/docs/best-practices/accessibility.md +0 -601
- package/docs/best-practices/common-patterns.md +0 -516
- package/docs/best-practices/deployment.md +0 -1103
- package/docs/best-practices/performance.md +0 -1328
- package/docs/best-practices/security.md +0 -940
- package/docs/best-practices/testing.md +0 -1034
- package/docs/rbac/compliance/compliance-guide.md +0 -544
- package/docs/standards/01-architecture-standard.md +0 -44
- package/docs/standards/02-api-and-rpc-standard.md +0 -39
- package/docs/standards/03-component-standard.md +0 -32
- package/docs/standards/04-code-style-standard.md +0 -32
- package/docs/standards/05-security-standard.md +0 -44
- package/docs/standards/06-testing-and-docs-standard.md +0 -29
- package/docs/standards/pace-core-compliance.md +0 -432
- package/scripts/audit/core/checks/accessibility.cjs +0 -197
- package/scripts/audit/core/checks/api-usage.cjs +0 -191
- package/scripts/audit/core/checks/bundle.cjs +0 -142
- package/scripts/audit/core/checks/compliance.cjs +0 -2706
- package/scripts/audit/core/checks/config.cjs +0 -54
- package/scripts/audit/core/checks/coverage.cjs +0 -84
- package/scripts/audit/core/checks/dependencies.cjs +0 -994
- package/scripts/audit/core/checks/documentation.cjs +0 -268
- package/scripts/audit/core/checks/environment.cjs +0 -116
- package/scripts/audit/core/checks/error-handling.cjs +0 -340
- package/scripts/audit/core/checks/forms.cjs +0 -172
- package/scripts/audit/core/checks/heuristics.cjs +0 -68
- package/scripts/audit/core/checks/hooks.cjs +0 -334
- package/scripts/audit/core/checks/imports.cjs +0 -244
- package/scripts/audit/core/checks/performance.cjs +0 -325
- package/scripts/audit/core/checks/routes.cjs +0 -117
- package/scripts/audit/core/checks/state.cjs +0 -130
- package/scripts/audit/core/checks/structure.cjs +0 -65
- package/scripts/audit/core/checks/style.cjs +0 -584
- package/scripts/audit/core/checks/testing.cjs +0 -122
- package/scripts/audit/core/checks/typescript.cjs +0 -61
- package/scripts/audit/core/scanner.cjs +0 -199
- package/scripts/audit/core/utils.cjs +0 -137
- package/scripts/audit/index.cjs +0 -223
- package/scripts/audit/reporters/console.cjs +0 -151
- package/scripts/audit/reporters/json.cjs +0 -54
- package/scripts/audit/reporters/markdown.cjs +0 -124
- package/scripts/audit-consuming-app.cjs +0 -86
- package/src/components/DataTable/components/DataTableBody.tsx +0 -454
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
- package/src/components/DataTable/components/ExpandButton.tsx +0 -113
- package/src/components/DataTable/components/GroupHeader.tsx +0 -54
- package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
- package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
- package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
- package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
- package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
- package/src/components/DataTable/core/DataTableContext.tsx +0 -216
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
- package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
- package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
- package/src/components/DataTable/utils/debugTools.ts +0 -514
- package/src/eslint-rules/pace-core-compliance.js +0 -638
- package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
- package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
- package/src/rbac/components/NavigationProvider.test.tsx +0 -481
- package/src/rbac/components/NavigationProvider.tsx +0 -345
- package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
- package/src/rbac/components/PagePermissionProvider.tsx +0 -279
- package/src/rbac/components/PermissionEnforcer.tsx +0 -312
- package/src/rbac/components/RoleBasedRouter.tsx +0 -440
- package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
- package/src/rbac/components/SecureDataProvider.tsx +0 -339
- package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
- package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
- package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
- package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
- package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
- package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
|
@@ -1,33 +1,172 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
} from
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
1
|
+
import { useAppConfig, useOrganisationSecurity } from './chunk-VBCS3DUA.js';
|
|
2
|
+
import { useEventService, useUnifiedAuth, useOrganisations } from './chunk-FTCRZOG2.js';
|
|
3
|
+
import { OrganisationContextRequiredError, getRBACLogger, resolveAppContext, getPageScopeType, ContextValidator, getPermissionMap, getRoleContext, getAccessLevel, isPermittedCached, isPermitted, isSuperAdmin } from './chunk-ZFYPMX46.js';
|
|
4
|
+
import { getCurrentAppName } from './chunk-OJ4SKRSV.js';
|
|
5
|
+
import { cn } from './chunk-7ILTDCL2.js';
|
|
6
|
+
import { createLogger, logger } from './chunk-TTRFSOKR.js';
|
|
7
|
+
import * as React2 from 'react';
|
|
8
|
+
import { useRef, useMemo, useState, useCallback, useEffect } from 'react';
|
|
9
|
+
import * as TooltipPrimitive from '@radix-ui/react-tooltip';
|
|
10
|
+
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
11
|
+
import { Slot } from '@radix-ui/react-slot';
|
|
12
|
+
import { createClient } from '@supabase/supabase-js';
|
|
13
|
+
|
|
14
|
+
function useEvents() {
|
|
15
|
+
const eventService = useEventService();
|
|
16
|
+
const rawEvents = eventService.getEvents();
|
|
17
|
+
const selectedEvent = eventService.getSelectedEvent();
|
|
18
|
+
const isLoading = eventService.isLoading();
|
|
19
|
+
const error = eventService.getError();
|
|
20
|
+
const prevEventsRef = useRef([]);
|
|
21
|
+
const prevEventsIdsRef = useRef("");
|
|
22
|
+
const currentEventsIds = rawEvents.map((e) => e.event_id || e.id).join(",");
|
|
23
|
+
const eventsChanged = currentEventsIds !== prevEventsIdsRef.current;
|
|
24
|
+
if (eventsChanged) {
|
|
25
|
+
prevEventsRef.current = rawEvents;
|
|
26
|
+
prevEventsIdsRef.current = currentEventsIds;
|
|
27
|
+
}
|
|
28
|
+
const events = useMemo(() => {
|
|
29
|
+
return prevEventsRef.current;
|
|
30
|
+
}, [currentEventsIds]);
|
|
31
|
+
const setSelectedEventCallback = useMemo(
|
|
32
|
+
() => (event) => eventService.setSelectedEvent(event),
|
|
33
|
+
[eventService]
|
|
34
|
+
);
|
|
35
|
+
const refreshEventsCallback = useMemo(
|
|
36
|
+
() => () => eventService.refreshEvents(),
|
|
37
|
+
[eventService]
|
|
38
|
+
);
|
|
39
|
+
const clearEventSelectionCallback = useMemo(
|
|
40
|
+
() => () => eventService.clearEventSelection(),
|
|
41
|
+
[eventService]
|
|
42
|
+
);
|
|
43
|
+
return useMemo(() => ({
|
|
44
|
+
events,
|
|
45
|
+
selectedEvent,
|
|
46
|
+
isLoading,
|
|
47
|
+
error,
|
|
48
|
+
setSelectedEvent: setSelectedEventCallback,
|
|
49
|
+
refreshEvents: refreshEventsCallback,
|
|
50
|
+
clearEventSelection: clearEventSelectionCallback
|
|
51
|
+
}), [events, selectedEvent?.event_id, isLoading, error?.message, setSelectedEventCallback, refreshEventsCallback, clearEventSelectionCallback]);
|
|
52
|
+
}
|
|
53
|
+
var TooltipProvider = TooltipPrimitive.Provider;
|
|
54
|
+
var TooltipRoot = TooltipPrimitive.Root;
|
|
55
|
+
var TooltipTrigger = TooltipPrimitive.Trigger;
|
|
56
|
+
var TooltipContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
|
|
57
|
+
TooltipPrimitive.Content,
|
|
58
|
+
{
|
|
59
|
+
ref,
|
|
60
|
+
sideOffset,
|
|
61
|
+
className: cn(
|
|
62
|
+
"z-50 overflow-hidden rounded-md border bg-main-500 px-3 py-1.5 text-sm text-main-50 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
|
|
63
|
+
className
|
|
64
|
+
),
|
|
65
|
+
...props
|
|
66
|
+
}
|
|
67
|
+
));
|
|
68
|
+
TooltipContent.displayName = TooltipPrimitive.Content.displayName;
|
|
69
|
+
var Tooltip = React2.forwardRef(({ children, content, delayDuration = 200 }, ref) => /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
|
|
70
|
+
/* @__PURE__ */ jsx(TooltipTrigger, { ref, asChild: true, children: /* @__PURE__ */ jsx("span", { children }) }),
|
|
71
|
+
/* @__PURE__ */ jsx(TooltipContent, { children: content })
|
|
72
|
+
] }) }));
|
|
73
|
+
Tooltip.displayName = "Tooltip";
|
|
74
|
+
function getButtonClasses(variant = "default", size = "default") {
|
|
75
|
+
const baseClasses = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50";
|
|
76
|
+
const variantClasses = {
|
|
77
|
+
default: "bg-main-600 text-main-50 shadow hover:bg-acc-400",
|
|
78
|
+
destructive: "bg-acc-600 text-acc-50 shadow-sm hover:bg-acc-400",
|
|
79
|
+
outline: "border border-main-300 bg-background shadow-sm hover:bg-acc-400",
|
|
80
|
+
secondary: "bg-sec-100 text-sec-900 shadow-sm hover:bg-acc-400",
|
|
81
|
+
ghost: "hover:bg-acc-400",
|
|
82
|
+
link: "text-main-700 underline-offset-4 hover:underline hover:drop-shadow-lg hover:drop-shadow-acc-400"
|
|
83
|
+
};
|
|
84
|
+
const sizeClasses = {
|
|
85
|
+
default: "h-9 px-4 py-2",
|
|
86
|
+
sm: "h-8 rounded-md px-3 text-xs",
|
|
87
|
+
lg: "h-10 rounded-md px-8",
|
|
88
|
+
icon: "size-8"
|
|
89
|
+
};
|
|
90
|
+
return `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`;
|
|
91
|
+
}
|
|
92
|
+
var Button = React2.forwardRef(
|
|
93
|
+
({ className, variant, size, asChild = false, type = "button", disabled, ...props }, ref) => {
|
|
94
|
+
const Comp = asChild ? Slot : "button";
|
|
95
|
+
return /* @__PURE__ */ jsx(
|
|
96
|
+
Comp,
|
|
97
|
+
{
|
|
98
|
+
className: cn(getButtonClasses(variant, size), className),
|
|
99
|
+
ref,
|
|
100
|
+
type: !asChild ? type : void 0,
|
|
101
|
+
disabled,
|
|
102
|
+
"aria-disabled": disabled ? "true" : void 0,
|
|
103
|
+
...props
|
|
104
|
+
}
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
);
|
|
108
|
+
Button.displayName = "Button";
|
|
109
|
+
function ButtonGroup({
|
|
110
|
+
children,
|
|
111
|
+
orientation = "horizontal",
|
|
112
|
+
variant,
|
|
113
|
+
size,
|
|
114
|
+
className,
|
|
115
|
+
spacing = "sm"
|
|
116
|
+
}) {
|
|
117
|
+
const spacingClasses = {
|
|
118
|
+
none: "",
|
|
119
|
+
sm: orientation === "horizontal" ? "space-x-1" : "space-y-1",
|
|
120
|
+
md: orientation === "horizontal" ? "space-x-2" : "space-y-2",
|
|
121
|
+
lg: orientation === "horizontal" ? "space-x-4" : "space-y-4"
|
|
122
|
+
};
|
|
123
|
+
return /* @__PURE__ */ jsx(
|
|
124
|
+
"fieldset",
|
|
125
|
+
{
|
|
126
|
+
className: cn(
|
|
127
|
+
"flex",
|
|
128
|
+
orientation === "horizontal" ? "flex-row items-center" : "flex-col",
|
|
129
|
+
spacingClasses[spacing],
|
|
130
|
+
className
|
|
131
|
+
),
|
|
132
|
+
role: "group",
|
|
133
|
+
children: React2.Children.map(children, (child) => {
|
|
134
|
+
if (React2.isValidElement(child) && child.type) {
|
|
135
|
+
const componentType = child.type;
|
|
136
|
+
if (componentType.displayName === "Button") {
|
|
137
|
+
const childProps = child.props;
|
|
138
|
+
return React2.cloneElement(child, {
|
|
139
|
+
variant: childProps.variant || variant,
|
|
140
|
+
size: childProps.size || size,
|
|
141
|
+
...childProps
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return child;
|
|
146
|
+
})
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
var IconButton = React2.forwardRef(
|
|
151
|
+
({ icon, className, size = "icon", "aria-label": ariaLabel, tooltip, ...props }, ref) => {
|
|
152
|
+
const button = /* @__PURE__ */ jsx(
|
|
153
|
+
Button,
|
|
154
|
+
{
|
|
155
|
+
ref,
|
|
156
|
+
size,
|
|
157
|
+
className: cn("shrink-0", className),
|
|
158
|
+
"aria-label": ariaLabel,
|
|
159
|
+
...props,
|
|
160
|
+
children: icon
|
|
161
|
+
}
|
|
162
|
+
);
|
|
163
|
+
if (tooltip) {
|
|
164
|
+
return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, children: button });
|
|
165
|
+
}
|
|
166
|
+
return button;
|
|
167
|
+
}
|
|
168
|
+
);
|
|
169
|
+
IconButton.displayName = "IconButton";
|
|
31
170
|
|
|
32
171
|
// src/rbac/utils/clientSecurity.ts
|
|
33
172
|
var SECURE_CLIENT_SYMBOL = Symbol("pace-core-secure-client");
|
|
@@ -61,11 +200,8 @@ See: https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/rbac/ge
|
|
|
61
200
|
function markClientAsSecure(client) {
|
|
62
201
|
client[SECURE_CLIENT_SYMBOL] = true;
|
|
63
202
|
}
|
|
64
|
-
|
|
65
|
-
// src/rbac/secureClient.ts
|
|
66
|
-
import { createClient } from "@supabase/supabase-js";
|
|
67
203
|
var _SecureSupabaseClient = class _SecureSupabaseClient {
|
|
68
|
-
constructor(supabaseUrl, supabaseKey, organisationId, eventId, appId,
|
|
204
|
+
constructor(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2 = false, existingClient) {
|
|
69
205
|
this.edgeFunctionClient = null;
|
|
70
206
|
this.usesExistingClient = false;
|
|
71
207
|
this.supabaseUrl = supabaseUrl;
|
|
@@ -73,7 +209,7 @@ var _SecureSupabaseClient = class _SecureSupabaseClient {
|
|
|
73
209
|
this.organisationId = organisationId;
|
|
74
210
|
this.eventId = eventId;
|
|
75
211
|
this.appId = appId;
|
|
76
|
-
this.isSuperAdmin =
|
|
212
|
+
this.isSuperAdmin = isSuperAdmin2;
|
|
77
213
|
if (existingClient) {
|
|
78
214
|
this.supabase = existingClient;
|
|
79
215
|
this.usesExistingClient = true;
|
|
@@ -422,200 +558,12 @@ _SecureSupabaseClient.GLOBAL_RPC_ALLOWLIST = /* @__PURE__ */ new Set([
|
|
|
422
558
|
"data_rbac_apps_list"
|
|
423
559
|
]);
|
|
424
560
|
var SecureSupabaseClient = _SecureSupabaseClient;
|
|
425
|
-
function createSecureClient(supabaseUrl, supabaseKey, organisationId, eventId, appId,
|
|
426
|
-
return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId,
|
|
561
|
+
function createSecureClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2 = false) {
|
|
562
|
+
return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2);
|
|
427
563
|
}
|
|
428
|
-
function fromSupabaseClient(client, organisationId, eventId, appId,
|
|
429
|
-
return new SecureSupabaseClient("", "", organisationId, eventId, appId,
|
|
564
|
+
function fromSupabaseClient(client, organisationId, eventId, appId, isSuperAdmin2 = false) {
|
|
565
|
+
return new SecureSupabaseClient("", "", organisationId, eventId, appId, isSuperAdmin2, client);
|
|
430
566
|
}
|
|
431
|
-
|
|
432
|
-
// src/rbac/hooks/useResolvedScope.ts
|
|
433
|
-
import { useEffect, useState, useRef, useMemo } from "react";
|
|
434
|
-
var log = createLogger("useResolvedScope");
|
|
435
|
-
var appIdCache = /* @__PURE__ */ new Map();
|
|
436
|
-
var CACHE_TTL = 5 * 60 * 1e3;
|
|
437
|
-
function useResolvedScope({
|
|
438
|
-
supabase,
|
|
439
|
-
selectedOrganisationId,
|
|
440
|
-
selectedEventId
|
|
441
|
-
}) {
|
|
442
|
-
const [resolvedScope, setResolvedScope] = useState(null);
|
|
443
|
-
const [isLoading, setIsLoading] = useState(true);
|
|
444
|
-
const [error, setError] = useState(null);
|
|
445
|
-
const stableScopeRef = useRef({
|
|
446
|
-
organisationId: "",
|
|
447
|
-
appId: "",
|
|
448
|
-
eventId: void 0
|
|
449
|
-
});
|
|
450
|
-
useEffect(() => {
|
|
451
|
-
if (resolvedScope) {
|
|
452
|
-
const newScope = {
|
|
453
|
-
organisationId: resolvedScope.organisationId || "",
|
|
454
|
-
appId: resolvedScope.appId || "",
|
|
455
|
-
eventId: resolvedScope.eventId
|
|
456
|
-
};
|
|
457
|
-
if (stableScopeRef.current.organisationId !== newScope.organisationId || stableScopeRef.current.eventId !== newScope.eventId || stableScopeRef.current.appId !== newScope.appId) {
|
|
458
|
-
stableScopeRef.current = {
|
|
459
|
-
organisationId: newScope.organisationId,
|
|
460
|
-
appId: newScope.appId,
|
|
461
|
-
eventId: newScope.eventId
|
|
462
|
-
};
|
|
463
|
-
}
|
|
464
|
-
} else {
|
|
465
|
-
stableScopeRef.current = { organisationId: "", appId: "", eventId: void 0 };
|
|
466
|
-
}
|
|
467
|
-
}, [resolvedScope]);
|
|
468
|
-
const appName = getCurrentAppName();
|
|
469
|
-
const stableScope = stableScopeRef.current;
|
|
470
|
-
useEffect(() => {
|
|
471
|
-
let cancelled = false;
|
|
472
|
-
const resolveScope = async () => {
|
|
473
|
-
if (!supabase && !selectedOrganisationId && !selectedEventId) {
|
|
474
|
-
if (!cancelled) {
|
|
475
|
-
setResolvedScope(null);
|
|
476
|
-
setIsLoading(false);
|
|
477
|
-
setError(null);
|
|
478
|
-
}
|
|
479
|
-
return;
|
|
480
|
-
}
|
|
481
|
-
setIsLoading(true);
|
|
482
|
-
setError(null);
|
|
483
|
-
try {
|
|
484
|
-
const appName2 = getCurrentAppName();
|
|
485
|
-
let appId = void 0;
|
|
486
|
-
if (supabase && appName2) {
|
|
487
|
-
try {
|
|
488
|
-
const { data: session } = await supabase.auth.getSession();
|
|
489
|
-
if (!session?.session) {
|
|
490
|
-
log.debug(`Skipping app resolution for "${appName2}" - user not authenticated`);
|
|
491
|
-
} else {
|
|
492
|
-
const cached = appIdCache.get(appName2);
|
|
493
|
-
const now = Date.now();
|
|
494
|
-
if (cached && now - cached.timestamp < CACHE_TTL) {
|
|
495
|
-
appId = cached.appId;
|
|
496
|
-
} else {
|
|
497
|
-
const { data: app, error: error2 } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).eq("is_active", true).single();
|
|
498
|
-
if (error2) {
|
|
499
|
-
if (error2.code === "406" || error2.code === "PGRST116" || error2.message?.includes("406")) {
|
|
500
|
-
log.debug(`App resolution blocked by RLS for "${appName2}" - user may not be authenticated`);
|
|
501
|
-
appId = void 0;
|
|
502
|
-
} else {
|
|
503
|
-
const { data: inactiveApp } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).single();
|
|
504
|
-
if (inactiveApp) {
|
|
505
|
-
log.error(`App "${appName2}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
|
|
506
|
-
appId = void 0;
|
|
507
|
-
} else {
|
|
508
|
-
log.error(`App "${appName2}" not found in rbac_apps table`, { error: error2 });
|
|
509
|
-
appId = void 0;
|
|
510
|
-
}
|
|
511
|
-
}
|
|
512
|
-
} else if (app) {
|
|
513
|
-
appId = app.id;
|
|
514
|
-
appIdCache.set(appName2, { appId, timestamp: now });
|
|
515
|
-
}
|
|
516
|
-
}
|
|
517
|
-
}
|
|
518
|
-
} catch (error2) {
|
|
519
|
-
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
520
|
-
if (!errorMessage.includes("406") && !errorMessage.includes("PGRST116")) {
|
|
521
|
-
log.error("Unexpected error resolving app ID:", error2);
|
|
522
|
-
} else {
|
|
523
|
-
log.debug("App resolution skipped - authentication required");
|
|
524
|
-
}
|
|
525
|
-
}
|
|
526
|
-
}
|
|
527
|
-
const initialScope = {
|
|
528
|
-
organisationId: selectedOrganisationId || void 0,
|
|
529
|
-
eventId: selectedEventId || void 0,
|
|
530
|
-
appId
|
|
531
|
-
};
|
|
532
|
-
if (appName2 === "PORTAL" || appName2 === "ADMIN") {
|
|
533
|
-
if (!cancelled) {
|
|
534
|
-
const optionalContextScope = {
|
|
535
|
-
organisationId: void 0,
|
|
536
|
-
eventId: void 0,
|
|
537
|
-
appId: appId || void 0
|
|
538
|
-
};
|
|
539
|
-
setResolvedScope(optionalContextScope);
|
|
540
|
-
setError(null);
|
|
541
|
-
setIsLoading(false);
|
|
542
|
-
}
|
|
543
|
-
return;
|
|
544
|
-
}
|
|
545
|
-
const { ContextValidator: ContextValidator2 } = await import("./contextValidator-5OGXSPKS.js");
|
|
546
|
-
const validation = await ContextValidator2.resolveScopeForPage(
|
|
547
|
-
initialScope,
|
|
548
|
-
"organisation",
|
|
549
|
-
// Default to organisation scope when no page context
|
|
550
|
-
appName2 || void 0,
|
|
551
|
-
supabase
|
|
552
|
-
);
|
|
553
|
-
if (!validation.isValid) {
|
|
554
|
-
if (selectedEventId) {
|
|
555
|
-
if (!cancelled) {
|
|
556
|
-
const eventScope = {
|
|
557
|
-
organisationId: void 0,
|
|
558
|
-
// Will be derived from event during permission check
|
|
559
|
-
eventId: selectedEventId,
|
|
560
|
-
appId: appId || void 0
|
|
561
|
-
};
|
|
562
|
-
setResolvedScope(eventScope);
|
|
563
|
-
setError(null);
|
|
564
|
-
setIsLoading(false);
|
|
565
|
-
}
|
|
566
|
-
return;
|
|
567
|
-
}
|
|
568
|
-
if (!cancelled) {
|
|
569
|
-
setResolvedScope(null);
|
|
570
|
-
setError(validation.error || new Error("Context validation failed"));
|
|
571
|
-
setIsLoading(false);
|
|
572
|
-
}
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
if (!cancelled) {
|
|
576
|
-
setResolvedScope(validation.resolvedScope);
|
|
577
|
-
setError(null);
|
|
578
|
-
setIsLoading(false);
|
|
579
|
-
}
|
|
580
|
-
} catch (err) {
|
|
581
|
-
if (!cancelled) {
|
|
582
|
-
setError(err);
|
|
583
|
-
setIsLoading(false);
|
|
584
|
-
}
|
|
585
|
-
}
|
|
586
|
-
};
|
|
587
|
-
resolveScope();
|
|
588
|
-
return () => {
|
|
589
|
-
cancelled = true;
|
|
590
|
-
};
|
|
591
|
-
}, [selectedOrganisationId, selectedEventId, supabase]);
|
|
592
|
-
const allowsOptionalContexts = appName === "PORTAL" || appName === "ADMIN";
|
|
593
|
-
const hasValidScope = allowsOptionalContexts ? true : stableScope.appId || stableScope.organisationId;
|
|
594
|
-
const finalScope = useMemo(() => {
|
|
595
|
-
if (!hasValidScope) {
|
|
596
|
-
return allowsOptionalContexts ? {} : null;
|
|
597
|
-
}
|
|
598
|
-
const scope = {};
|
|
599
|
-
if (stableScope.organisationId) {
|
|
600
|
-
scope.organisationId = stableScope.organisationId;
|
|
601
|
-
}
|
|
602
|
-
if (stableScope.eventId) {
|
|
603
|
-
scope.eventId = stableScope.eventId;
|
|
604
|
-
}
|
|
605
|
-
if (stableScope.appId) {
|
|
606
|
-
scope.appId = stableScope.appId;
|
|
607
|
-
}
|
|
608
|
-
return scope;
|
|
609
|
-
}, [hasValidScope, allowsOptionalContexts, stableScope.organisationId, stableScope.eventId, stableScope.appId]);
|
|
610
|
-
return {
|
|
611
|
-
resolvedScope: finalScope,
|
|
612
|
-
isLoading,
|
|
613
|
-
error
|
|
614
|
-
};
|
|
615
|
-
}
|
|
616
|
-
|
|
617
|
-
// src/rbac/hooks/useRBAC.ts
|
|
618
|
-
import { useState as useState2, useEffect as useEffect2, useCallback, useMemo as useMemo2 } from "react";
|
|
619
567
|
function mapAccessLevelToEventRole(level) {
|
|
620
568
|
switch (level) {
|
|
621
569
|
case "viewer":
|
|
@@ -645,13 +593,13 @@ function useRBAC(pageId) {
|
|
|
645
593
|
selectedEvent,
|
|
646
594
|
eventLoading
|
|
647
595
|
} = useUnifiedAuth();
|
|
648
|
-
const [globalRole, setGlobalRole] =
|
|
649
|
-
const [organisationRole, setOrganisationRole] =
|
|
650
|
-
const [eventAppRole, setEventAppRole] =
|
|
651
|
-
const [permissionMap, setPermissionMap] =
|
|
652
|
-
const [currentScope, setCurrentScope] =
|
|
653
|
-
const [isLoading, setIsLoading] =
|
|
654
|
-
const [error, setError] =
|
|
596
|
+
const [globalRole, setGlobalRole] = useState(null);
|
|
597
|
+
const [organisationRole, setOrganisationRole] = useState(null);
|
|
598
|
+
const [eventAppRole, setEventAppRole] = useState(null);
|
|
599
|
+
const [permissionMap, setPermissionMap] = useState({});
|
|
600
|
+
const [currentScope, setCurrentScope] = useState(null);
|
|
601
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
602
|
+
const [error, setError] = useState(null);
|
|
655
603
|
const resetState = useCallback(() => {
|
|
656
604
|
setGlobalRole(null);
|
|
657
605
|
setOrganisationRole(null);
|
|
@@ -777,12 +725,12 @@ function useRBAC(pageId) {
|
|
|
777
725
|
},
|
|
778
726
|
[globalRole, organisationRole, permissionMap]
|
|
779
727
|
);
|
|
780
|
-
const
|
|
781
|
-
const isOrgAdmin =
|
|
782
|
-
const isEventAdmin =
|
|
783
|
-
const canManageOrganisation =
|
|
784
|
-
const canManageEvent =
|
|
785
|
-
|
|
728
|
+
const isSuperAdmin2 = useMemo(() => globalRole === "super_admin" || permissionMap["*"] === true, [globalRole, permissionMap]);
|
|
729
|
+
const isOrgAdmin = useMemo(() => organisationRole === "org_admin" || isSuperAdmin2, [organisationRole, isSuperAdmin2]);
|
|
730
|
+
const isEventAdmin = useMemo(() => eventAppRole === "event_admin" || isSuperAdmin2, [eventAppRole, isSuperAdmin2]);
|
|
731
|
+
const canManageOrganisation = useMemo(() => isSuperAdmin2 || organisationRole === "org_admin", [isSuperAdmin2, organisationRole]);
|
|
732
|
+
const canManageEvent = useMemo(() => isSuperAdmin2 || eventAppRole === "event_admin", [isSuperAdmin2, eventAppRole]);
|
|
733
|
+
useEffect(() => {
|
|
786
734
|
loadRBACContext();
|
|
787
735
|
}, [loadRBACContext, appName, eventLoading, selectedEvent?.event_id, user, session, selectedOrganisation?.id, orgContextReady, orgLoading]);
|
|
788
736
|
return {
|
|
@@ -791,7 +739,7 @@ function useRBAC(pageId) {
|
|
|
791
739
|
organisationRole,
|
|
792
740
|
eventAppRole,
|
|
793
741
|
hasGlobalPermission,
|
|
794
|
-
isSuperAdmin,
|
|
742
|
+
isSuperAdmin: isSuperAdmin2,
|
|
795
743
|
isOrgAdmin,
|
|
796
744
|
isEventAdmin,
|
|
797
745
|
canManageOrganisation,
|
|
@@ -800,20 +748,131 @@ function useRBAC(pageId) {
|
|
|
800
748
|
error
|
|
801
749
|
};
|
|
802
750
|
}
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
751
|
+
var log = createLogger("useResolvedScope");
|
|
752
|
+
var appIdCache = /* @__PURE__ */ new Map();
|
|
753
|
+
var CACHE_TTL = 5 * 60 * 1e3;
|
|
754
|
+
function useResolvedScope({
|
|
755
|
+
supabase,
|
|
756
|
+
selectedOrganisationId,
|
|
757
|
+
selectedEventId,
|
|
758
|
+
selectedEventOrganisationId
|
|
759
|
+
}) {
|
|
760
|
+
const immediateOrganisationId = selectedEventOrganisationId || selectedOrganisationId || void 0;
|
|
761
|
+
const immediateEventId = selectedEventId || void 0;
|
|
762
|
+
const [appId, setAppId] = useState(void 0);
|
|
763
|
+
const [isResolvingAppId, setIsResolvingAppId] = useState(false);
|
|
764
|
+
const [error, setError] = useState(null);
|
|
765
|
+
const appName = getCurrentAppName();
|
|
766
|
+
useEffect(() => {
|
|
767
|
+
let cancelled = false;
|
|
768
|
+
const resolveAppId = async () => {
|
|
769
|
+
if (!supabase && !selectedOrganisationId && !selectedEventId) {
|
|
770
|
+
if (!cancelled) {
|
|
771
|
+
setAppId(void 0);
|
|
772
|
+
setIsResolvingAppId(false);
|
|
773
|
+
setError(null);
|
|
774
|
+
}
|
|
775
|
+
return;
|
|
776
|
+
}
|
|
777
|
+
setIsResolvingAppId(true);
|
|
778
|
+
setError(null);
|
|
779
|
+
try {
|
|
780
|
+
const appName2 = getCurrentAppName();
|
|
781
|
+
let resolvedAppId = void 0;
|
|
782
|
+
if (supabase && appName2) {
|
|
783
|
+
try {
|
|
784
|
+
const { data: session } = await supabase.auth.getSession();
|
|
785
|
+
if (!session?.session) {
|
|
786
|
+
log.debug(`Skipping app resolution for "${appName2}" - user not authenticated`);
|
|
787
|
+
} else {
|
|
788
|
+
const cached = appIdCache.get(appName2);
|
|
789
|
+
const now = Date.now();
|
|
790
|
+
if (cached && now - cached.timestamp < CACHE_TTL) {
|
|
791
|
+
resolvedAppId = cached.appId;
|
|
792
|
+
} else {
|
|
793
|
+
const { data: app, error: error2 } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).eq("is_active", true).single();
|
|
794
|
+
if (error2) {
|
|
795
|
+
if (error2.code === "406" || error2.code === "PGRST116" || error2.message?.includes("406")) {
|
|
796
|
+
log.debug(`App resolution blocked by RLS for "${appName2}" - user may not be authenticated`);
|
|
797
|
+
resolvedAppId = void 0;
|
|
798
|
+
} else {
|
|
799
|
+
const { data: inactiveApp } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).single();
|
|
800
|
+
if (inactiveApp) {
|
|
801
|
+
log.error(`App "${appName2}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
|
|
802
|
+
resolvedAppId = void 0;
|
|
803
|
+
} else {
|
|
804
|
+
log.error(`App "${appName2}" not found in rbac_apps table`, { error: error2 });
|
|
805
|
+
resolvedAppId = void 0;
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
} else if (app) {
|
|
809
|
+
resolvedAppId = app.id;
|
|
810
|
+
appIdCache.set(appName2, { appId: resolvedAppId, timestamp: now });
|
|
811
|
+
}
|
|
812
|
+
}
|
|
813
|
+
}
|
|
814
|
+
} catch (error2) {
|
|
815
|
+
const errorMessage = error2 instanceof Error ? error2.message : String(error2);
|
|
816
|
+
if (!errorMessage.includes("406") && !errorMessage.includes("PGRST116")) {
|
|
817
|
+
log.error("Unexpected error resolving app ID:", error2);
|
|
818
|
+
} else {
|
|
819
|
+
log.debug("App resolution skipped - authentication required");
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
if (!cancelled) {
|
|
824
|
+
setAppId(resolvedAppId);
|
|
825
|
+
setIsResolvingAppId(false);
|
|
826
|
+
setError(null);
|
|
827
|
+
}
|
|
828
|
+
} catch (err) {
|
|
829
|
+
if (!cancelled) {
|
|
830
|
+
setError(err);
|
|
831
|
+
setIsResolvingAppId(false);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
resolveAppId();
|
|
836
|
+
return () => {
|
|
837
|
+
cancelled = true;
|
|
838
|
+
};
|
|
839
|
+
}, [supabase, selectedOrganisationId, selectedEventId]);
|
|
840
|
+
const immediateScope = useMemo(() => {
|
|
841
|
+
if (appName === "PORTAL" || appName === "ADMIN") {
|
|
842
|
+
return {
|
|
843
|
+
organisationId: void 0,
|
|
844
|
+
eventId: void 0,
|
|
845
|
+
appId: appId || void 0
|
|
846
|
+
};
|
|
847
|
+
}
|
|
848
|
+
const scope = {};
|
|
849
|
+
if (immediateOrganisationId) {
|
|
850
|
+
scope.organisationId = immediateOrganisationId;
|
|
851
|
+
}
|
|
852
|
+
if (immediateEventId) {
|
|
853
|
+
scope.eventId = immediateEventId;
|
|
854
|
+
}
|
|
855
|
+
if (appId) {
|
|
856
|
+
scope.appId = appId;
|
|
857
|
+
}
|
|
858
|
+
if (!scope.organisationId && !scope.appId) {
|
|
859
|
+
return null;
|
|
860
|
+
}
|
|
861
|
+
return scope;
|
|
862
|
+
}, [immediateOrganisationId, immediateEventId, appId, appName]);
|
|
863
|
+
return {
|
|
864
|
+
resolvedScope: immediateScope,
|
|
865
|
+
isLoading: isResolvingAppId,
|
|
866
|
+
// Only true while appId resolves
|
|
867
|
+
error
|
|
868
|
+
};
|
|
869
|
+
}
|
|
806
870
|
function useAccessLevel(userId, scope) {
|
|
807
|
-
const [accessLevel, setAccessLevel] =
|
|
808
|
-
const [isLoading, setIsLoading] =
|
|
809
|
-
const [error, setError] =
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
const { appName: contextAppName } = useAppConfig();
|
|
813
|
-
appName = contextAppName;
|
|
814
|
-
} catch {
|
|
815
|
-
}
|
|
816
|
-
const fetchAccessLevel = useCallback2(async () => {
|
|
871
|
+
const [accessLevel, setAccessLevel] = useState("viewer");
|
|
872
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
873
|
+
const [error, setError] = useState(null);
|
|
874
|
+
const { appName } = useAppConfig();
|
|
875
|
+
const fetchAccessLevel = useCallback(async () => {
|
|
817
876
|
if (!userId) {
|
|
818
877
|
setAccessLevel("viewer");
|
|
819
878
|
setIsLoading(false);
|
|
@@ -822,7 +881,7 @@ function useAccessLevel(userId, scope) {
|
|
|
822
881
|
try {
|
|
823
882
|
setIsLoading(true);
|
|
824
883
|
setError(null);
|
|
825
|
-
const { isSuperAdmin: checkSuperAdmin } = await import(
|
|
884
|
+
const { isSuperAdmin: checkSuperAdmin } = await import('./api-Y4MQWOFW.js');
|
|
826
885
|
const isSuperAdminUser = await checkSuperAdmin(userId);
|
|
827
886
|
if (isSuperAdminUser) {
|
|
828
887
|
setAccessLevel("super");
|
|
@@ -846,10 +905,10 @@ function useAccessLevel(userId, scope) {
|
|
|
846
905
|
setIsLoading(false);
|
|
847
906
|
}
|
|
848
907
|
}, [userId, scope.organisationId, scope.eventId, scope.appId, appName]);
|
|
849
|
-
|
|
908
|
+
useEffect(() => {
|
|
850
909
|
fetchAccessLevel();
|
|
851
910
|
}, [fetchAccessLevel]);
|
|
852
|
-
return
|
|
911
|
+
return useMemo(() => ({
|
|
853
912
|
accessLevel,
|
|
854
913
|
isLoading,
|
|
855
914
|
error,
|
|
@@ -857,47 +916,6 @@ function useAccessLevel(userId, scope) {
|
|
|
857
916
|
}), [accessLevel, isLoading, error, fetchAccessLevel]);
|
|
858
917
|
}
|
|
859
918
|
|
|
860
|
-
// src/rbac/hooks/permissions/useCachedPermissions.ts
|
|
861
|
-
import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo4, useState as useState4 } from "react";
|
|
862
|
-
function useCachedPermissions(userId, scope) {
|
|
863
|
-
const [permissions, setPermissions] = useState4({});
|
|
864
|
-
const [isLoading, setIsLoading] = useState4(true);
|
|
865
|
-
const [error, setError] = useState4(null);
|
|
866
|
-
const fetchCachedPermissions = useCallback3(async () => {
|
|
867
|
-
if (!userId) {
|
|
868
|
-
setPermissions({});
|
|
869
|
-
setIsLoading(false);
|
|
870
|
-
return;
|
|
871
|
-
}
|
|
872
|
-
try {
|
|
873
|
-
setIsLoading(true);
|
|
874
|
-
setError(null);
|
|
875
|
-
const permissionMap = await getPermissionMap({ userId, scope });
|
|
876
|
-
setPermissions(permissionMap);
|
|
877
|
-
} catch (err) {
|
|
878
|
-
setError(err instanceof Error ? err : new Error("Failed to fetch cached permissions"));
|
|
879
|
-
} finally {
|
|
880
|
-
setIsLoading(false);
|
|
881
|
-
}
|
|
882
|
-
}, [userId, scope.organisationId, scope.eventId, scope.appId]);
|
|
883
|
-
const invalidateCache = useCallback3(() => {
|
|
884
|
-
fetchCachedPermissions();
|
|
885
|
-
}, [fetchCachedPermissions]);
|
|
886
|
-
useEffect4(() => {
|
|
887
|
-
fetchCachedPermissions();
|
|
888
|
-
}, [fetchCachedPermissions]);
|
|
889
|
-
return useMemo4(() => ({
|
|
890
|
-
permissions,
|
|
891
|
-
isLoading,
|
|
892
|
-
error,
|
|
893
|
-
invalidateCache,
|
|
894
|
-
refetch: fetchCachedPermissions
|
|
895
|
-
}), [permissions, isLoading, error, invalidateCache, fetchCachedPermissions]);
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
// src/rbac/hooks/permissions/useCan.ts
|
|
899
|
-
import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef2, useState as useState5 } from "react";
|
|
900
|
-
|
|
901
919
|
// src/rbac/utils/deep-equal.ts
|
|
902
920
|
function scopeEqual(a, b) {
|
|
903
921
|
if (a === b) {
|
|
@@ -911,27 +929,27 @@ function scopeEqual(a, b) {
|
|
|
911
929
|
|
|
912
930
|
// src/rbac/hooks/permissions/useCan.ts
|
|
913
931
|
function useCan(userId, scope, permission, pageId, useCache = true, precomputedSuperAdmin = null, appName) {
|
|
914
|
-
const [
|
|
932
|
+
const [isSuperAdmin2, setIsSuperAdmin] = useState(precomputedSuperAdmin ?? null);
|
|
915
933
|
const initialCan = precomputedSuperAdmin === true ? true : false;
|
|
916
934
|
const initialIsLoading = precomputedSuperAdmin === true ? false : true;
|
|
917
|
-
const [can, setCan] =
|
|
918
|
-
const [isLoading, setIsLoading] =
|
|
919
|
-
const [error, setError] =
|
|
935
|
+
const [can, setCan] = useState(initialCan);
|
|
936
|
+
const [isLoading, setIsLoading] = useState(initialIsLoading);
|
|
937
|
+
const [error, setError] = useState(null);
|
|
920
938
|
const isValidScope = scope && typeof scope === "object";
|
|
921
939
|
const organisationId = isValidScope ? scope.organisationId : void 0;
|
|
922
940
|
const eventId = isValidScope ? scope.eventId : void 0;
|
|
923
941
|
const appId = isValidScope ? scope.appId : void 0;
|
|
924
|
-
|
|
925
|
-
if (precomputedSuperAdmin === true &&
|
|
942
|
+
useEffect(() => {
|
|
943
|
+
if (precomputedSuperAdmin === true && isSuperAdmin2 !== true) {
|
|
926
944
|
setIsSuperAdmin(true);
|
|
927
945
|
setCan(true);
|
|
928
946
|
setIsLoading(false);
|
|
929
947
|
setError(null);
|
|
930
|
-
} else if (precomputedSuperAdmin === false &&
|
|
948
|
+
} else if (precomputedSuperAdmin === false && isSuperAdmin2 !== false) {
|
|
931
949
|
setIsSuperAdmin(false);
|
|
932
950
|
}
|
|
933
|
-
}, [precomputedSuperAdmin,
|
|
934
|
-
|
|
951
|
+
}, [precomputedSuperAdmin, isSuperAdmin2]);
|
|
952
|
+
useEffect(() => {
|
|
935
953
|
if (precomputedSuperAdmin === null) {
|
|
936
954
|
if (!userId) {
|
|
937
955
|
setIsSuperAdmin(false);
|
|
@@ -941,7 +959,7 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
941
959
|
const checkSuperAdmin = async () => {
|
|
942
960
|
const startTime = Date.now();
|
|
943
961
|
try {
|
|
944
|
-
const { isSuperAdmin: checkSuperAdmin2 } = await import(
|
|
962
|
+
const { isSuperAdmin: checkSuperAdmin2 } = await import('./api-Y4MQWOFW.js');
|
|
945
963
|
const timeoutWarning = setTimeout(() => {
|
|
946
964
|
if (!cancelled) {
|
|
947
965
|
console.warn("[useCan] Super admin check taking longer than 5 seconds", {
|
|
@@ -985,10 +1003,10 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
985
1003
|
};
|
|
986
1004
|
}
|
|
987
1005
|
}, [userId, precomputedSuperAdmin]);
|
|
988
|
-
|
|
1006
|
+
useEffect(() => {
|
|
989
1007
|
const isPagePermission = permission.includes(":page.") || !!pageId;
|
|
990
1008
|
const requiresOrgId = !isPagePermission;
|
|
991
|
-
if (
|
|
1009
|
+
if (isSuperAdmin2 === true) {
|
|
992
1010
|
return;
|
|
993
1011
|
}
|
|
994
1012
|
if (requiresOrgId && (!isValidScope || !organisationId || organisationId === null || typeof organisationId === "string" && organisationId.trim() === "")) {
|
|
@@ -1002,14 +1020,14 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
1002
1020
|
if (error?.message === "Organisation context is required for permission checks") {
|
|
1003
1021
|
setError(null);
|
|
1004
1022
|
}
|
|
1005
|
-
}, [isValidScope, organisationId, error, permission, pageId,
|
|
1006
|
-
const lastUserIdRef =
|
|
1007
|
-
|
|
1008
|
-
const lastPermissionRef =
|
|
1009
|
-
const lastPageIdRef =
|
|
1010
|
-
const lastUseCacheRef =
|
|
1011
|
-
const lastIsSuperAdminRef =
|
|
1012
|
-
const stableScope =
|
|
1023
|
+
}, [isValidScope, organisationId, error, permission, pageId, isSuperAdmin2]);
|
|
1024
|
+
const lastUserIdRef = useRef(null);
|
|
1025
|
+
useRef(null);
|
|
1026
|
+
const lastPermissionRef = useRef(null);
|
|
1027
|
+
const lastPageIdRef = useRef(null);
|
|
1028
|
+
const lastUseCacheRef = useRef(null);
|
|
1029
|
+
const lastIsSuperAdminRef = useRef(null);
|
|
1030
|
+
const stableScope = useMemo(() => {
|
|
1013
1031
|
if (!isValidScope) {
|
|
1014
1032
|
return null;
|
|
1015
1033
|
}
|
|
@@ -1019,12 +1037,12 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
1019
1037
|
appId
|
|
1020
1038
|
};
|
|
1021
1039
|
}, [isValidScope, organisationId, eventId, appId]);
|
|
1022
|
-
const prevScopeRef =
|
|
1023
|
-
|
|
1040
|
+
const prevScopeRef = useRef(null);
|
|
1041
|
+
useEffect(() => {
|
|
1024
1042
|
const scopeChanged = !scopeEqual(prevScopeRef.current, stableScope);
|
|
1025
|
-
const isSuperAdminChanged = lastIsSuperAdminRef.current !==
|
|
1043
|
+
const isSuperAdminChanged = lastIsSuperAdminRef.current !== isSuperAdmin2;
|
|
1026
1044
|
if (lastUserIdRef.current !== userId || scopeChanged || lastPermissionRef.current !== permission || lastPageIdRef.current !== pageId || lastUseCacheRef.current !== useCache || isSuperAdminChanged) {
|
|
1027
|
-
lastIsSuperAdminRef.current =
|
|
1045
|
+
lastIsSuperAdminRef.current = isSuperAdmin2;
|
|
1028
1046
|
lastUserIdRef.current = userId;
|
|
1029
1047
|
prevScopeRef.current = stableScope;
|
|
1030
1048
|
lastPermissionRef.current = permission;
|
|
@@ -1036,13 +1054,13 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
1036
1054
|
setIsLoading(false);
|
|
1037
1055
|
return;
|
|
1038
1056
|
}
|
|
1039
|
-
if (
|
|
1057
|
+
if (isSuperAdmin2 === true) {
|
|
1040
1058
|
setCan(true);
|
|
1041
1059
|
setIsLoading(false);
|
|
1042
1060
|
setError(null);
|
|
1043
1061
|
return;
|
|
1044
1062
|
}
|
|
1045
|
-
if (
|
|
1063
|
+
if (isSuperAdmin2 === null) {
|
|
1046
1064
|
setIsLoading(true);
|
|
1047
1065
|
setCan(false);
|
|
1048
1066
|
setError(null);
|
|
@@ -1078,7 +1096,7 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
1078
1096
|
...eventId ? { eventId } : {},
|
|
1079
1097
|
...appId ? { appId } : {}
|
|
1080
1098
|
};
|
|
1081
|
-
const result = useCache ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName) : await isPermitted({ userId, scope: validScope, permission, pageId }, appName,
|
|
1099
|
+
const result = useCache ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName) : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, isSuperAdmin2 === false ? false : null);
|
|
1082
1100
|
setCan(result);
|
|
1083
1101
|
} catch (err) {
|
|
1084
1102
|
const logger2 = getRBACLogger();
|
|
@@ -1092,8 +1110,8 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
1092
1110
|
};
|
|
1093
1111
|
checkPermission();
|
|
1094
1112
|
}
|
|
1095
|
-
}, [userId, stableScope, permission, pageId, useCache, appName,
|
|
1096
|
-
const refetch =
|
|
1113
|
+
}, [userId, stableScope, permission, pageId, useCache, appName, isSuperAdmin2]);
|
|
1114
|
+
const refetch = useCallback(async () => {
|
|
1097
1115
|
if (!userId) {
|
|
1098
1116
|
setCan(false);
|
|
1099
1117
|
setIsLoading(false);
|
|
@@ -1130,105 +1148,18 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
|
|
|
1130
1148
|
setIsLoading(false);
|
|
1131
1149
|
}
|
|
1132
1150
|
}, [userId, isValidScope, organisationId, eventId, appId, permission, pageId, useCache, appName]);
|
|
1133
|
-
return
|
|
1151
|
+
return useMemo(() => ({
|
|
1134
1152
|
can,
|
|
1135
1153
|
isLoading,
|
|
1136
1154
|
error,
|
|
1137
1155
|
refetch
|
|
1138
1156
|
}), [can, isLoading, error, refetch]);
|
|
1139
1157
|
}
|
|
1140
|
-
|
|
1141
|
-
// src/rbac/hooks/permissions/useHasAllPermissions.ts
|
|
1142
|
-
import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo6, useState as useState6 } from "react";
|
|
1143
|
-
function useHasAllPermissions(userId, scope, permissions, useCache = true) {
|
|
1144
|
-
const [hasAll, setHasAll] = useState6(false);
|
|
1145
|
-
const [isLoading, setIsLoading] = useState6(true);
|
|
1146
|
-
const [error, setError] = useState6(null);
|
|
1147
|
-
const checkAllPermissions = useCallback5(async () => {
|
|
1148
|
-
if (!userId || permissions.length === 0) {
|
|
1149
|
-
setHasAll(false);
|
|
1150
|
-
setIsLoading(false);
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
|
-
try {
|
|
1154
|
-
setIsLoading(true);
|
|
1155
|
-
setError(null);
|
|
1156
|
-
let hasAllPermissions = true;
|
|
1157
|
-
for (const permission of permissions) {
|
|
1158
|
-
const result = useCache ? await isPermittedCached({ userId, scope, permission }) : await isPermitted({ userId, scope, permission });
|
|
1159
|
-
if (!result) {
|
|
1160
|
-
hasAllPermissions = false;
|
|
1161
|
-
break;
|
|
1162
|
-
}
|
|
1163
|
-
}
|
|
1164
|
-
setHasAll(hasAllPermissions);
|
|
1165
|
-
} catch (err) {
|
|
1166
|
-
setError(err instanceof Error ? err : new Error("Failed to check permissions"));
|
|
1167
|
-
setHasAll(false);
|
|
1168
|
-
} finally {
|
|
1169
|
-
setIsLoading(false);
|
|
1170
|
-
}
|
|
1171
|
-
}, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
|
|
1172
|
-
useEffect6(() => {
|
|
1173
|
-
checkAllPermissions();
|
|
1174
|
-
}, [checkAllPermissions]);
|
|
1175
|
-
return useMemo6(() => ({
|
|
1176
|
-
hasAll,
|
|
1177
|
-
isLoading,
|
|
1178
|
-
error,
|
|
1179
|
-
refetch: checkAllPermissions
|
|
1180
|
-
}), [hasAll, isLoading, error, checkAllPermissions]);
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
// src/rbac/hooks/permissions/useHasAnyPermission.ts
|
|
1184
|
-
import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo7, useState as useState7 } from "react";
|
|
1185
|
-
function useHasAnyPermission(userId, scope, permissions, useCache = true) {
|
|
1186
|
-
const [hasAny, setHasAny] = useState7(false);
|
|
1187
|
-
const [isLoading, setIsLoading] = useState7(true);
|
|
1188
|
-
const [error, setError] = useState7(null);
|
|
1189
|
-
const checkAnyPermission = useCallback6(async () => {
|
|
1190
|
-
if (!userId || permissions.length === 0) {
|
|
1191
|
-
setHasAny(false);
|
|
1192
|
-
setIsLoading(false);
|
|
1193
|
-
return;
|
|
1194
|
-
}
|
|
1195
|
-
try {
|
|
1196
|
-
setIsLoading(true);
|
|
1197
|
-
setError(null);
|
|
1198
|
-
let hasAnyPermission = false;
|
|
1199
|
-
for (const permission of permissions) {
|
|
1200
|
-
const result = useCache ? await isPermittedCached({ userId, scope, permission }) : await isPermitted({ userId, scope, permission });
|
|
1201
|
-
if (result) {
|
|
1202
|
-
hasAnyPermission = true;
|
|
1203
|
-
break;
|
|
1204
|
-
}
|
|
1205
|
-
}
|
|
1206
|
-
setHasAny(hasAnyPermission);
|
|
1207
|
-
} catch (err) {
|
|
1208
|
-
setError(err instanceof Error ? err : new Error("Failed to check permissions"));
|
|
1209
|
-
setHasAny(false);
|
|
1210
|
-
} finally {
|
|
1211
|
-
setIsLoading(false);
|
|
1212
|
-
}
|
|
1213
|
-
}, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
|
|
1214
|
-
useEffect7(() => {
|
|
1215
|
-
checkAnyPermission();
|
|
1216
|
-
}, [checkAnyPermission]);
|
|
1217
|
-
return useMemo7(() => ({
|
|
1218
|
-
hasAny,
|
|
1219
|
-
isLoading,
|
|
1220
|
-
error,
|
|
1221
|
-
refetch: checkAnyPermission
|
|
1222
|
-
}), [hasAny, isLoading, error, checkAnyPermission]);
|
|
1223
|
-
}
|
|
1224
|
-
|
|
1225
|
-
// src/rbac/hooks/permissions/useMultiplePermissions.ts
|
|
1226
|
-
import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo8, useState as useState8 } from "react";
|
|
1227
1158
|
function useMultiplePermissions(userId, scope, permissions, useCache = true) {
|
|
1228
|
-
const [results, setResults] =
|
|
1229
|
-
const [isLoading, setIsLoading] =
|
|
1230
|
-
const [error, setError] =
|
|
1231
|
-
const checkPermissions =
|
|
1159
|
+
const [results, setResults] = useState({});
|
|
1160
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
1161
|
+
const [error, setError] = useState(null);
|
|
1162
|
+
const checkPermissions = useCallback(async () => {
|
|
1232
1163
|
if (!userId || permissions.length === 0) {
|
|
1233
1164
|
setResults({});
|
|
1234
1165
|
setIsLoading(false);
|
|
@@ -1250,29 +1181,26 @@ function useMultiplePermissions(userId, scope, permissions, useCache = true) {
|
|
|
1250
1181
|
setIsLoading(false);
|
|
1251
1182
|
}
|
|
1252
1183
|
}, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
|
|
1253
|
-
|
|
1184
|
+
useEffect(() => {
|
|
1254
1185
|
checkPermissions();
|
|
1255
1186
|
}, [checkPermissions]);
|
|
1256
|
-
return
|
|
1187
|
+
return useMemo(() => ({
|
|
1257
1188
|
results,
|
|
1258
1189
|
isLoading,
|
|
1259
1190
|
error,
|
|
1260
1191
|
refetch: checkPermissions
|
|
1261
1192
|
}), [results, isLoading, error, checkPermissions]);
|
|
1262
1193
|
}
|
|
1263
|
-
|
|
1264
|
-
// src/rbac/hooks/permissions/usePermissions.ts
|
|
1265
|
-
import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo9, useRef as useRef3, useState as useState9 } from "react";
|
|
1266
1194
|
function usePermissions(userId, organisationId, eventId, appId) {
|
|
1267
|
-
const [permissions, setPermissions] =
|
|
1268
|
-
const [isLoading, setIsLoading] =
|
|
1269
|
-
const [error, setError] =
|
|
1270
|
-
const [fetchTrigger, setFetchTrigger] =
|
|
1271
|
-
const isFetchingRef =
|
|
1195
|
+
const [permissions, setPermissions] = useState({});
|
|
1196
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
1197
|
+
const [error, setError] = useState(null);
|
|
1198
|
+
const [fetchTrigger, setFetchTrigger] = useState(0);
|
|
1199
|
+
const isFetchingRef = useRef(false);
|
|
1272
1200
|
const logger2 = getRBACLogger();
|
|
1273
|
-
const prevValuesRef =
|
|
1201
|
+
const prevValuesRef = useRef({ userId, organisationId, eventId, appId });
|
|
1274
1202
|
const orgId = organisationId || "";
|
|
1275
|
-
|
|
1203
|
+
useEffect(() => {
|
|
1276
1204
|
if (!userId) {
|
|
1277
1205
|
return;
|
|
1278
1206
|
}
|
|
@@ -1287,16 +1215,15 @@ function usePermissions(userId, organisationId, eventId, appId) {
|
|
|
1287
1215
|
setError(null);
|
|
1288
1216
|
}
|
|
1289
1217
|
}, [userId, organisationId, error, orgId]);
|
|
1290
|
-
|
|
1218
|
+
useEffect(() => {
|
|
1291
1219
|
const paramsChanged = prevValuesRef.current.userId !== userId || prevValuesRef.current.organisationId !== organisationId || prevValuesRef.current.eventId !== eventId || prevValuesRef.current.appId !== appId;
|
|
1292
1220
|
if (paramsChanged) {
|
|
1293
|
-
if (prevValuesRef.current.appId !== appId)
|
|
1294
|
-
}
|
|
1221
|
+
if (prevValuesRef.current.appId !== appId) ;
|
|
1295
1222
|
prevValuesRef.current = { userId, organisationId, eventId, appId };
|
|
1296
1223
|
setFetchTrigger((prev) => prev + 1);
|
|
1297
1224
|
}
|
|
1298
1225
|
}, [userId, organisationId, eventId, appId, logger2]);
|
|
1299
|
-
|
|
1226
|
+
useEffect(() => {
|
|
1300
1227
|
const fetchPermissions = async () => {
|
|
1301
1228
|
if (isFetchingRef.current) {
|
|
1302
1229
|
return;
|
|
@@ -1343,25 +1270,25 @@ function usePermissions(userId, organisationId, eventId, appId) {
|
|
|
1343
1270
|
};
|
|
1344
1271
|
fetchPermissions();
|
|
1345
1272
|
}, [fetchTrigger, userId, organisationId, eventId, appId]);
|
|
1346
|
-
const hasPermission =
|
|
1273
|
+
const hasPermission = useCallback((permission) => {
|
|
1347
1274
|
if (permissions["*"]) {
|
|
1348
1275
|
return true;
|
|
1349
1276
|
}
|
|
1350
1277
|
return permissions[permission] === true;
|
|
1351
1278
|
}, [permissions]);
|
|
1352
|
-
const hasAnyPermission =
|
|
1279
|
+
const hasAnyPermission = useCallback((permissionList) => {
|
|
1353
1280
|
if (permissions["*"]) {
|
|
1354
1281
|
return true;
|
|
1355
1282
|
}
|
|
1356
1283
|
return permissionList.some((p) => permissions[p] === true);
|
|
1357
1284
|
}, [permissions]);
|
|
1358
|
-
const hasAllPermissions =
|
|
1285
|
+
const hasAllPermissions = useCallback((permissionList) => {
|
|
1359
1286
|
if (permissions["*"]) {
|
|
1360
1287
|
return true;
|
|
1361
1288
|
}
|
|
1362
1289
|
return permissionList.every((p) => permissions[p] === true);
|
|
1363
1290
|
}, [permissions]);
|
|
1364
|
-
const refetch =
|
|
1291
|
+
const refetch = useCallback(async () => {
|
|
1365
1292
|
if (isFetchingRef.current) {
|
|
1366
1293
|
return;
|
|
1367
1294
|
}
|
|
@@ -1395,7 +1322,7 @@ function usePermissions(userId, organisationId, eventId, appId) {
|
|
|
1395
1322
|
isFetchingRef.current = false;
|
|
1396
1323
|
}
|
|
1397
1324
|
}, [userId, organisationId, eventId, appId]);
|
|
1398
|
-
return
|
|
1325
|
+
return useMemo(() => ({
|
|
1399
1326
|
permissions,
|
|
1400
1327
|
isLoading,
|
|
1401
1328
|
error,
|
|
@@ -1405,12 +1332,57 @@ function usePermissions(userId, organisationId, eventId, appId) {
|
|
|
1405
1332
|
refetch
|
|
1406
1333
|
}), [permissions, isLoading, error, hasPermission, hasAnyPermission, hasAllPermissions, refetch]);
|
|
1407
1334
|
}
|
|
1408
|
-
|
|
1409
|
-
// src/rbac/hooks/useResourcePermissions.ts
|
|
1410
|
-
import { useMemo as useMemo10 } from "react";
|
|
1411
1335
|
function useResourcePermissions(resource, options = {}) {
|
|
1412
1336
|
const { enableRead = false, requireScope = true } = options;
|
|
1337
|
+
const logger2 = createLogger("ResourcePermissions");
|
|
1413
1338
|
const { user, supabase } = useUnifiedAuth();
|
|
1339
|
+
const [isSuperAdminUser, setIsSuperAdminUser] = useState(null);
|
|
1340
|
+
const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(() => !!user?.id);
|
|
1341
|
+
const lastCheckedUserIdRef = useRef(null);
|
|
1342
|
+
const isCheckingRef = useRef(false);
|
|
1343
|
+
useEffect(() => {
|
|
1344
|
+
if (lastCheckedUserIdRef.current === user?.id && isSuperAdminUser !== null) {
|
|
1345
|
+
return;
|
|
1346
|
+
}
|
|
1347
|
+
if (isCheckingRef.current) {
|
|
1348
|
+
return;
|
|
1349
|
+
}
|
|
1350
|
+
const checkSuperAdminStatus = async () => {
|
|
1351
|
+
if (!user?.id) {
|
|
1352
|
+
setIsSuperAdminUser(false);
|
|
1353
|
+
setIsCheckingSuperAdmin(false);
|
|
1354
|
+
lastCheckedUserIdRef.current = null;
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
isCheckingRef.current = true;
|
|
1358
|
+
lastCheckedUserIdRef.current = user.id;
|
|
1359
|
+
const startTime = Date.now();
|
|
1360
|
+
setIsCheckingSuperAdmin(true);
|
|
1361
|
+
const timeoutId = setTimeout(() => {
|
|
1362
|
+
logger2.warn("useResourcePermissions", "Super admin check taking longer than 5 seconds", {
|
|
1363
|
+
userId: user?.id,
|
|
1364
|
+
elapsedMs: Date.now() - startTime
|
|
1365
|
+
});
|
|
1366
|
+
}, 5e3);
|
|
1367
|
+
try {
|
|
1368
|
+
const superAdminStatus = await isSuperAdmin(user.id);
|
|
1369
|
+
setIsSuperAdminUser(superAdminStatus);
|
|
1370
|
+
} catch (error2) {
|
|
1371
|
+
const elapsed = Date.now() - startTime;
|
|
1372
|
+
logger2.error("useResourcePermissions", "Error checking super admin status", {
|
|
1373
|
+
userId: user?.id,
|
|
1374
|
+
error: error2,
|
|
1375
|
+
elapsedMs: elapsed
|
|
1376
|
+
});
|
|
1377
|
+
setIsSuperAdminUser(false);
|
|
1378
|
+
} finally {
|
|
1379
|
+
clearTimeout(timeoutId);
|
|
1380
|
+
setIsCheckingSuperAdmin(false);
|
|
1381
|
+
isCheckingRef.current = false;
|
|
1382
|
+
}
|
|
1383
|
+
};
|
|
1384
|
+
checkSuperAdminStatus();
|
|
1385
|
+
}, [user?.id, logger2]);
|
|
1414
1386
|
const { selectedOrganisation } = useOrganisations();
|
|
1415
1387
|
let selectedEvent = null;
|
|
1416
1388
|
try {
|
|
@@ -1421,7 +1393,8 @@ function useResourcePermissions(resource, options = {}) {
|
|
|
1421
1393
|
const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
|
|
1422
1394
|
supabase,
|
|
1423
1395
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
1424
|
-
selectedEventId: selectedEvent?.event_id || null
|
|
1396
|
+
selectedEventId: selectedEvent?.event_id || null,
|
|
1397
|
+
selectedEventOrganisationId: selectedEvent?.organisation_id || null
|
|
1425
1398
|
});
|
|
1426
1399
|
const scope = resolvedScope || {
|
|
1427
1400
|
organisationId: selectedOrganisation?.id || "",
|
|
@@ -1443,8 +1416,8 @@ function useResourcePermissions(resource, options = {}) {
|
|
|
1443
1416
|
// Pass resource name as pageId when appId is available to enable page permission checks
|
|
1444
1417
|
true,
|
|
1445
1418
|
// useCache
|
|
1446
|
-
|
|
1447
|
-
// precomputedSuperAdmin -
|
|
1419
|
+
isSuperAdminUser,
|
|
1420
|
+
// precomputedSuperAdmin - null if checking, false/true if checked
|
|
1448
1421
|
void 0
|
|
1449
1422
|
// appName
|
|
1450
1423
|
);
|
|
@@ -1456,8 +1429,8 @@ function useResourcePermissions(resource, options = {}) {
|
|
|
1456
1429
|
// Pass resource name as pageId when appId is available to enable page permission checks
|
|
1457
1430
|
true,
|
|
1458
1431
|
// useCache
|
|
1459
|
-
|
|
1460
|
-
// precomputedSuperAdmin -
|
|
1432
|
+
isSuperAdminUser,
|
|
1433
|
+
// precomputedSuperAdmin - null if checking, false/true if checked
|
|
1461
1434
|
void 0
|
|
1462
1435
|
// appName
|
|
1463
1436
|
);
|
|
@@ -1469,8 +1442,8 @@ function useResourcePermissions(resource, options = {}) {
|
|
|
1469
1442
|
// Pass resource name as pageId when appId is available to enable page permission checks
|
|
1470
1443
|
true,
|
|
1471
1444
|
// useCache
|
|
1472
|
-
|
|
1473
|
-
// precomputedSuperAdmin -
|
|
1445
|
+
isSuperAdminUser,
|
|
1446
|
+
// precomputedSuperAdmin - null if checking, false/true if checked
|
|
1474
1447
|
void 0
|
|
1475
1448
|
// appName
|
|
1476
1449
|
);
|
|
@@ -1482,16 +1455,17 @@ function useResourcePermissions(resource, options = {}) {
|
|
|
1482
1455
|
// Pass resource name as pageId when appId is available to enable page permission checks
|
|
1483
1456
|
true,
|
|
1484
1457
|
// useCache
|
|
1485
|
-
|
|
1486
|
-
// precomputedSuperAdmin -
|
|
1458
|
+
isSuperAdminUser,
|
|
1459
|
+
// precomputedSuperAdmin - null if checking, false/true if checked
|
|
1487
1460
|
void 0
|
|
1488
1461
|
// appName
|
|
1489
1462
|
);
|
|
1490
|
-
const isLoading =
|
|
1463
|
+
const isLoading = useMemo(() => {
|
|
1491
1464
|
const waitingForScope = requireScope && scopeLoading;
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1465
|
+
const waitingForSuperAdmin = isSuperAdminUser === null && isCheckingSuperAdmin;
|
|
1466
|
+
return waitingForScope || waitingForSuperAdmin || createLoading || updateLoading || deleteLoading || enableRead && readLoading;
|
|
1467
|
+
}, [scopeLoading, requireScope, isSuperAdminUser, isCheckingSuperAdmin, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
|
|
1468
|
+
const error = useMemo(() => {
|
|
1495
1469
|
if (scopeError) return scopeError;
|
|
1496
1470
|
if (createError) return createError;
|
|
1497
1471
|
if (updateError) return updateError;
|
|
@@ -1499,85 +1473,155 @@ function useResourcePermissions(resource, options = {}) {
|
|
|
1499
1473
|
if (enableRead && readError) return readError;
|
|
1500
1474
|
return null;
|
|
1501
1475
|
}, [scopeError, createError, updateError, deleteError, readError, enableRead]);
|
|
1502
|
-
return
|
|
1503
|
-
|
|
1504
|
-
if (
|
|
1505
|
-
return false;
|
|
1506
|
-
}
|
|
1507
|
-
return canCreateResult;
|
|
1508
|
-
},
|
|
1509
|
-
canUpdate: (res) => {
|
|
1510
|
-
if (res !== resource) {
|
|
1511
|
-
return false;
|
|
1512
|
-
}
|
|
1513
|
-
return canUpdateResult;
|
|
1514
|
-
},
|
|
1515
|
-
canDelete: (res) => {
|
|
1516
|
-
if (res !== resource) {
|
|
1517
|
-
return false;
|
|
1518
|
-
}
|
|
1519
|
-
return canDeleteResult;
|
|
1520
|
-
},
|
|
1521
|
-
canRead: (res) => {
|
|
1522
|
-
if (!enableRead) {
|
|
1476
|
+
return useMemo(() => {
|
|
1477
|
+
const createSuperAdminAwarePermission = (result) => {
|
|
1478
|
+
if (isSuperAdminUser === true) {
|
|
1523
1479
|
return true;
|
|
1524
1480
|
}
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1481
|
+
return result;
|
|
1482
|
+
};
|
|
1483
|
+
return {
|
|
1484
|
+
canCreate: (res) => {
|
|
1485
|
+
if (res !== resource) {
|
|
1486
|
+
return false;
|
|
1487
|
+
}
|
|
1488
|
+
return createSuperAdminAwarePermission(canCreateResult);
|
|
1489
|
+
},
|
|
1490
|
+
canUpdate: (res) => {
|
|
1491
|
+
if (res !== resource) {
|
|
1492
|
+
return false;
|
|
1493
|
+
}
|
|
1494
|
+
return createSuperAdminAwarePermission(canUpdateResult);
|
|
1495
|
+
},
|
|
1496
|
+
canDelete: (res) => {
|
|
1497
|
+
if (res !== resource) {
|
|
1498
|
+
return false;
|
|
1499
|
+
}
|
|
1500
|
+
return createSuperAdminAwarePermission(canDeleteResult);
|
|
1501
|
+
},
|
|
1502
|
+
canRead: (res) => {
|
|
1503
|
+
if (!enableRead) {
|
|
1504
|
+
return true;
|
|
1505
|
+
}
|
|
1506
|
+
if (res !== resource) {
|
|
1507
|
+
return false;
|
|
1508
|
+
}
|
|
1509
|
+
return createSuperAdminAwarePermission(canReadResult);
|
|
1510
|
+
},
|
|
1511
|
+
scope,
|
|
1512
|
+
isLoading: isCheckingSuperAdmin || isLoading,
|
|
1513
|
+
error
|
|
1514
|
+
};
|
|
1515
|
+
}, [
|
|
1534
1516
|
resource,
|
|
1517
|
+
isSuperAdminUser,
|
|
1518
|
+
isCheckingSuperAdmin,
|
|
1535
1519
|
canCreateResult,
|
|
1536
|
-
// This is already the boolean 'can' value
|
|
1537
1520
|
canUpdateResult,
|
|
1538
|
-
// This is already the boolean 'can' value
|
|
1539
1521
|
canDeleteResult,
|
|
1540
|
-
// This is already the boolean 'can' value
|
|
1541
1522
|
canReadResult,
|
|
1542
|
-
// This is already the boolean 'can' value
|
|
1543
1523
|
enableRead,
|
|
1544
1524
|
scope,
|
|
1545
1525
|
isLoading,
|
|
1546
1526
|
error
|
|
1547
1527
|
]);
|
|
1548
1528
|
}
|
|
1549
|
-
|
|
1550
|
-
// src/rbac/hooks/useRoleManagement.ts
|
|
1551
|
-
import { useState as useState10, useCallback as useCallback9 } from "react";
|
|
1552
1529
|
function useRoleManagement() {
|
|
1553
1530
|
const { user, supabase } = useUnifiedAuth();
|
|
1554
|
-
const [isLoading, setIsLoading] =
|
|
1555
|
-
const [error, setError] =
|
|
1531
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
1532
|
+
const [error, setError] = useState(null);
|
|
1556
1533
|
if (!supabase) {
|
|
1557
1534
|
throw new Error("useRoleManagement requires a Supabase client. Ensure UnifiedAuthProvider is configured.");
|
|
1558
1535
|
}
|
|
1559
|
-
const revokeEventAppRole =
|
|
1536
|
+
const revokeEventAppRole = useCallback(async (params) => {
|
|
1560
1537
|
setIsLoading(true);
|
|
1561
1538
|
setError(null);
|
|
1562
1539
|
try {
|
|
1563
|
-
const
|
|
1540
|
+
const contextId = `${params.event_id}:${params.app_id}`;
|
|
1541
|
+
const rpcParams = {
|
|
1564
1542
|
p_user_id: params.user_id,
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
p_role: params.role,
|
|
1543
|
+
p_role_type: "event_app",
|
|
1544
|
+
p_role_name: params.role,
|
|
1545
|
+
p_context_id: contextId,
|
|
1569
1546
|
p_revoked_by: params.revoked_by || user?.id || void 0
|
|
1570
|
-
}
|
|
1547
|
+
};
|
|
1548
|
+
if (import.meta.env.MODE === "development") {
|
|
1549
|
+
console.log("[useRoleManagement] revokeEventAppRole called with:", rpcParams);
|
|
1550
|
+
}
|
|
1551
|
+
const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", rpcParams);
|
|
1571
1552
|
if (rpcError) {
|
|
1572
|
-
|
|
1553
|
+
if (import.meta.env.MODE === "development") {
|
|
1554
|
+
console.error("[useRoleManagement] RPC error:", {
|
|
1555
|
+
message: rpcError.message,
|
|
1556
|
+
details: rpcError.details,
|
|
1557
|
+
hint: rpcError.hint,
|
|
1558
|
+
code: rpcError.code,
|
|
1559
|
+
fullError: rpcError
|
|
1560
|
+
});
|
|
1561
|
+
}
|
|
1562
|
+
const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
|
|
1563
|
+
throw new Error(errorMessage);
|
|
1564
|
+
}
|
|
1565
|
+
if (import.meta.env.MODE === "development") {
|
|
1566
|
+
console.log("[useRoleManagement] RPC response:", {
|
|
1567
|
+
data,
|
|
1568
|
+
error: rpcError,
|
|
1569
|
+
dataType: Array.isArray(data) ? "array" : typeof data,
|
|
1570
|
+
dataLength: Array.isArray(data) ? data.length : "N/A"
|
|
1571
|
+
});
|
|
1572
|
+
}
|
|
1573
|
+
if (!data || !Array.isArray(data) || data.length === 0) {
|
|
1574
|
+
const errorMsg = "No response from database - role revocation may have failed";
|
|
1575
|
+
if (import.meta.env.MODE === "development") {
|
|
1576
|
+
console.error("[useRoleManagement] Empty or null data response:", {
|
|
1577
|
+
data,
|
|
1578
|
+
dataType: typeof data,
|
|
1579
|
+
isArray: Array.isArray(data),
|
|
1580
|
+
length: Array.isArray(data) ? data.length : "N/A"
|
|
1581
|
+
});
|
|
1582
|
+
}
|
|
1583
|
+
throw new Error(errorMsg);
|
|
1584
|
+
}
|
|
1585
|
+
const result = data[0];
|
|
1586
|
+
if (import.meta.env.MODE === "development") {
|
|
1587
|
+
console.log("[useRoleManagement] RPC result:", {
|
|
1588
|
+
success: result?.success,
|
|
1589
|
+
message: result?.message,
|
|
1590
|
+
error_code: result?.error_code,
|
|
1591
|
+
revoked_count: result?.revoked_count,
|
|
1592
|
+
fullResult: result
|
|
1593
|
+
});
|
|
1594
|
+
}
|
|
1595
|
+
if (!result || result.success !== true) {
|
|
1596
|
+
const errorMessage = result?.message || result?.error_code || "Role revocation failed";
|
|
1597
|
+
if (import.meta.env.MODE === "development") {
|
|
1598
|
+
console.error("[useRoleManagement] Role revocation failed:", {
|
|
1599
|
+
result,
|
|
1600
|
+
errorMessage,
|
|
1601
|
+
fullData: data,
|
|
1602
|
+
rpcParams
|
|
1603
|
+
});
|
|
1604
|
+
}
|
|
1605
|
+
return {
|
|
1606
|
+
success: false,
|
|
1607
|
+
message: result?.message || void 0,
|
|
1608
|
+
error: errorMessage
|
|
1609
|
+
};
|
|
1573
1610
|
}
|
|
1574
1611
|
return {
|
|
1575
|
-
success:
|
|
1576
|
-
message:
|
|
1577
|
-
error:
|
|
1612
|
+
success: true,
|
|
1613
|
+
message: result.message || "Role revoked successfully",
|
|
1614
|
+
error: void 0
|
|
1578
1615
|
};
|
|
1579
1616
|
} catch (err) {
|
|
1580
1617
|
const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
|
|
1618
|
+
if (import.meta.env.MODE === "development") {
|
|
1619
|
+
console.error("[useRoleManagement] Exception in revokeEventAppRole:", {
|
|
1620
|
+
error: err,
|
|
1621
|
+
errorMessage,
|
|
1622
|
+
params
|
|
1623
|
+
});
|
|
1624
|
+
}
|
|
1581
1625
|
setError(err instanceof Error ? err : new Error(errorMessage));
|
|
1582
1626
|
return {
|
|
1583
1627
|
success: false,
|
|
@@ -1586,8 +1630,8 @@ function useRoleManagement() {
|
|
|
1586
1630
|
} finally {
|
|
1587
1631
|
setIsLoading(false);
|
|
1588
1632
|
}
|
|
1589
|
-
}, [user?.id]);
|
|
1590
|
-
const grantEventAppRole =
|
|
1633
|
+
}, [user?.id, supabase]);
|
|
1634
|
+
const grantEventAppRole = useCallback(async (params) => {
|
|
1591
1635
|
setIsLoading(true);
|
|
1592
1636
|
setError(null);
|
|
1593
1637
|
try {
|
|
@@ -1626,7 +1670,7 @@ function useRoleManagement() {
|
|
|
1626
1670
|
setIsLoading(false);
|
|
1627
1671
|
}
|
|
1628
1672
|
}, [user?.id]);
|
|
1629
|
-
const revokeRoleById =
|
|
1673
|
+
const revokeRoleById = useCallback(async (roleId) => {
|
|
1630
1674
|
setIsLoading(true);
|
|
1631
1675
|
setError(null);
|
|
1632
1676
|
try {
|
|
@@ -1643,13 +1687,28 @@ function useRoleManagement() {
|
|
|
1643
1687
|
p_revoked_by: user?.id || void 0
|
|
1644
1688
|
});
|
|
1645
1689
|
if (rpcError) {
|
|
1646
|
-
|
|
1690
|
+
const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
|
|
1691
|
+
throw new Error(errorMessage);
|
|
1647
1692
|
}
|
|
1648
1693
|
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
1694
|
+
if (!result) {
|
|
1695
|
+
return {
|
|
1696
|
+
success: false,
|
|
1697
|
+
error: void 0
|
|
1698
|
+
};
|
|
1699
|
+
}
|
|
1700
|
+
if (result.success === false) {
|
|
1701
|
+
const errorMessage = result.message || result.error_code || "Role revocation failed";
|
|
1702
|
+
return {
|
|
1703
|
+
success: false,
|
|
1704
|
+
message: result.message || void 0,
|
|
1705
|
+
error: errorMessage
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1649
1708
|
return {
|
|
1650
|
-
success:
|
|
1651
|
-
message: result
|
|
1652
|
-
error:
|
|
1709
|
+
success: true,
|
|
1710
|
+
message: result.message || "Role revoked successfully",
|
|
1711
|
+
error: void 0
|
|
1653
1712
|
};
|
|
1654
1713
|
} catch (err) {
|
|
1655
1714
|
const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
|
|
@@ -1662,7 +1721,7 @@ function useRoleManagement() {
|
|
|
1662
1721
|
setIsLoading(false);
|
|
1663
1722
|
}
|
|
1664
1723
|
}, [user?.id, supabase]);
|
|
1665
|
-
const grantGlobalRole =
|
|
1724
|
+
const grantGlobalRole = useCallback(async (params) => {
|
|
1666
1725
|
setIsLoading(true);
|
|
1667
1726
|
setError(null);
|
|
1668
1727
|
try {
|
|
@@ -1701,7 +1760,7 @@ function useRoleManagement() {
|
|
|
1701
1760
|
setIsLoading(false);
|
|
1702
1761
|
}
|
|
1703
1762
|
}, [user?.id, supabase]);
|
|
1704
|
-
const revokeGlobalRole =
|
|
1763
|
+
const revokeGlobalRole = useCallback(async (params) => {
|
|
1705
1764
|
setIsLoading(true);
|
|
1706
1765
|
setError(null);
|
|
1707
1766
|
try {
|
|
@@ -1714,7 +1773,14 @@ function useRoleManagement() {
|
|
|
1714
1773
|
p_revoked_by: params.revoked_by || user?.id || void 0
|
|
1715
1774
|
});
|
|
1716
1775
|
if (rpcError) {
|
|
1717
|
-
|
|
1776
|
+
const errorParts = [
|
|
1777
|
+
rpcError.message,
|
|
1778
|
+
rpcError.details,
|
|
1779
|
+
rpcError.hint,
|
|
1780
|
+
rpcError.code ? `Error code: ${rpcError.code}` : null
|
|
1781
|
+
].filter(Boolean);
|
|
1782
|
+
const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
|
|
1783
|
+
throw new Error(errorMessage);
|
|
1718
1784
|
}
|
|
1719
1785
|
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
1720
1786
|
return {
|
|
@@ -1733,7 +1799,7 @@ function useRoleManagement() {
|
|
|
1733
1799
|
setIsLoading(false);
|
|
1734
1800
|
}
|
|
1735
1801
|
}, [user?.id, supabase]);
|
|
1736
|
-
const grantOrganisationRole =
|
|
1802
|
+
const grantOrganisationRole = useCallback(async (params) => {
|
|
1737
1803
|
setIsLoading(true);
|
|
1738
1804
|
setError(null);
|
|
1739
1805
|
try {
|
|
@@ -1772,7 +1838,7 @@ function useRoleManagement() {
|
|
|
1772
1838
|
setIsLoading(false);
|
|
1773
1839
|
}
|
|
1774
1840
|
}, [user?.id, supabase]);
|
|
1775
|
-
const revokeOrganisationRole =
|
|
1841
|
+
const revokeOrganisationRole = useCallback(async (params) => {
|
|
1776
1842
|
setIsLoading(true);
|
|
1777
1843
|
setError(null);
|
|
1778
1844
|
try {
|
|
@@ -1785,7 +1851,14 @@ function useRoleManagement() {
|
|
|
1785
1851
|
p_revoked_by: params.revoked_by || user?.id || void 0
|
|
1786
1852
|
});
|
|
1787
1853
|
if (rpcError) {
|
|
1788
|
-
|
|
1854
|
+
const errorParts = [
|
|
1855
|
+
rpcError.message,
|
|
1856
|
+
rpcError.details,
|
|
1857
|
+
rpcError.hint,
|
|
1858
|
+
rpcError.code ? `Error code: ${rpcError.code}` : null
|
|
1859
|
+
].filter(Boolean);
|
|
1860
|
+
const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
|
|
1861
|
+
throw new Error(errorMessage);
|
|
1789
1862
|
}
|
|
1790
1863
|
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
1791
1864
|
return {
|
|
@@ -1820,13 +1893,10 @@ function useRoleManagement() {
|
|
|
1820
1893
|
error
|
|
1821
1894
|
};
|
|
1822
1895
|
}
|
|
1823
|
-
|
|
1824
|
-
// src/rbac/hooks/useSecureSupabase.ts
|
|
1825
|
-
import { useMemo as useMemo11, useRef as useRef4 } from "react";
|
|
1826
1896
|
var secureClientCache = /* @__PURE__ */ new Map();
|
|
1827
1897
|
var MAX_CACHE_SIZE = 5;
|
|
1828
|
-
function getCacheKey(organisationId, eventId, appId,
|
|
1829
|
-
return `${organisationId || "no-org"}-${eventId || "no-event"}-${appId || "no-app"}-${
|
|
1898
|
+
function getCacheKey(organisationId, eventId, appId, isSuperAdmin2) {
|
|
1899
|
+
return `${organisationId || "no-org"}-${eventId || "no-event"}-${appId || "no-app"}-${isSuperAdmin2 ? "super" : "regular"}`;
|
|
1830
1900
|
}
|
|
1831
1901
|
function getSupabaseConfig() {
|
|
1832
1902
|
const getEnvVar = (key) => {
|
|
@@ -1852,28 +1922,26 @@ function useSecureSupabase(baseClient) {
|
|
|
1852
1922
|
const { selectedEvent } = eventsContext;
|
|
1853
1923
|
const eventLoading = "eventLoading" in eventsContext ? eventsContext.eventLoading : false;
|
|
1854
1924
|
const { superAdminContext } = useOrganisationSecurity();
|
|
1855
|
-
const
|
|
1925
|
+
const isSuperAdmin2 = superAdminContext.isSuperAdmin;
|
|
1856
1926
|
const { resolvedScope } = useResolvedScope({
|
|
1857
1927
|
supabase: authSupabase || null,
|
|
1858
1928
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
1859
|
-
selectedEventId: selectedEvent?.event_id || null
|
|
1929
|
+
selectedEventId: selectedEvent?.event_id || null,
|
|
1930
|
+
selectedEventOrganisationId: selectedEvent?.organisation_id || null
|
|
1860
1931
|
});
|
|
1861
|
-
const prevContextRef =
|
|
1932
|
+
const prevContextRef = useRef({
|
|
1862
1933
|
organisationId: void 0,
|
|
1863
1934
|
eventId: void 0,
|
|
1864
1935
|
appId: void 0
|
|
1865
1936
|
});
|
|
1866
|
-
return
|
|
1867
|
-
if (eventLoading) {
|
|
1868
|
-
return baseClient || authSupabase || null;
|
|
1869
|
-
}
|
|
1937
|
+
return useMemo(() => {
|
|
1870
1938
|
const organisationId = resolvedScope?.organisationId;
|
|
1871
1939
|
const eventId = resolvedScope?.eventId || selectedEvent?.event_id;
|
|
1872
1940
|
const appId = resolvedScope?.appId;
|
|
1873
|
-
const canCreateSecureClient = user?.id && (
|
|
1941
|
+
const canCreateSecureClient = user?.id && (isSuperAdmin2 || organisationId);
|
|
1874
1942
|
if (canCreateSecureClient) {
|
|
1875
1943
|
prevContextRef.current = { organisationId, eventId, appId };
|
|
1876
|
-
const cacheKey = getCacheKey(organisationId, eventId, appId,
|
|
1944
|
+
const cacheKey = getCacheKey(organisationId, eventId, appId, isSuperAdmin2);
|
|
1877
1945
|
const cachedClient = secureClientCache.get(cacheKey);
|
|
1878
1946
|
if (cachedClient) {
|
|
1879
1947
|
return cachedClient.getClient();
|
|
@@ -1886,14 +1954,14 @@ function useSecureSupabase(baseClient) {
|
|
|
1886
1954
|
return baseClient || authSupabase || null;
|
|
1887
1955
|
}
|
|
1888
1956
|
try {
|
|
1889
|
-
const effectiveOrganisationId =
|
|
1957
|
+
const effectiveOrganisationId = isSuperAdmin2 ? organisationId || null : organisationId;
|
|
1890
1958
|
const baseForSecureClient = baseClient || authSupabase || null;
|
|
1891
1959
|
const secureClient = baseForSecureClient ? fromSupabaseClient(
|
|
1892
1960
|
baseForSecureClient,
|
|
1893
1961
|
effectiveOrganisationId ?? null,
|
|
1894
1962
|
eventId,
|
|
1895
1963
|
appId,
|
|
1896
|
-
|
|
1964
|
+
isSuperAdmin2
|
|
1897
1965
|
) : createSecureClient(
|
|
1898
1966
|
config.url,
|
|
1899
1967
|
config.key,
|
|
@@ -1902,7 +1970,7 @@ function useSecureSupabase(baseClient) {
|
|
|
1902
1970
|
eventId,
|
|
1903
1971
|
appId,
|
|
1904
1972
|
// appId is string | undefined, UUID is string alias
|
|
1905
|
-
|
|
1973
|
+
isSuperAdmin2
|
|
1906
1974
|
// Pass super admin status for conditional filtering
|
|
1907
1975
|
);
|
|
1908
1976
|
secureClientCache.set(cacheKey, secureClient);
|
|
@@ -1926,31 +1994,10 @@ function useSecureSupabase(baseClient) {
|
|
|
1926
1994
|
selectedEvent?.event_id,
|
|
1927
1995
|
user?.id,
|
|
1928
1996
|
eventLoading,
|
|
1929
|
-
|
|
1997
|
+
isSuperAdmin2,
|
|
1930
1998
|
baseClient,
|
|
1931
1999
|
authSupabase
|
|
1932
2000
|
]);
|
|
1933
2001
|
}
|
|
1934
2002
|
|
|
1935
|
-
export {
|
|
1936
|
-
SECURE_CLIENT_SYMBOL,
|
|
1937
|
-
isSecureClient,
|
|
1938
|
-
warnIfInsecureClient,
|
|
1939
|
-
SecureSupabaseClient,
|
|
1940
|
-
createSecureClient,
|
|
1941
|
-
fromSupabaseClient,
|
|
1942
|
-
useResolvedScope,
|
|
1943
|
-
useRBAC,
|
|
1944
|
-
useAccessLevel,
|
|
1945
|
-
useCachedPermissions,
|
|
1946
|
-
scopeEqual,
|
|
1947
|
-
useCan,
|
|
1948
|
-
useHasAllPermissions,
|
|
1949
|
-
useHasAnyPermission,
|
|
1950
|
-
useMultiplePermissions,
|
|
1951
|
-
usePermissions,
|
|
1952
|
-
useResourcePermissions,
|
|
1953
|
-
useRoleManagement,
|
|
1954
|
-
useSecureSupabase
|
|
1955
|
-
};
|
|
1956
|
-
//# sourceMappingURL=chunk-HU2C6SSC.js.map
|
|
2003
|
+
export { Button, ButtonGroup, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };
|