@jmruthers/pace-core 0.5.189 → 0.5.191
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/core-usage-manifest.json +0 -4
- package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
- package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
- package/dist/{DataTable-GUFUNZ3N.js → DataTable-WKRZD47S.js} +8 -8
- package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +84 -25
- package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
- package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-FTSG5XH7.js} +4 -2
- package/dist/{api-YP7XD5L6.js → api-IHKALJZD.js} +4 -2
- package/dist/{chunk-VGZZXKBR.js → chunk-6LTQQAT6.js} +351 -157
- package/dist/chunk-6LTQQAT6.js.map +1 -0
- package/dist/{chunk-MX64ZF6I.js → chunk-6TQDD426.js} +15 -15
- package/dist/chunk-6TQDD426.js.map +1 -0
- package/dist/{chunk-YHCN776L.js → chunk-G37KK66H.js} +2 -75
- package/dist/chunk-G37KK66H.js.map +1 -0
- package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
- package/dist/chunk-HW3OVDUF.js.map +1 -0
- package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
- package/dist/chunk-I7PSE6JW.js.map +1 -0
- package/dist/{chunk-IM4QE42D.js → chunk-LOMZXPSN.js} +141 -326
- package/dist/chunk-LOMZXPSN.js.map +1 -0
- package/dist/chunk-OETXORNB.js +614 -0
- package/dist/chunk-OETXORNB.js.map +1 -0
- package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
- package/dist/{chunk-HEHYGYOX.js → chunk-ROXMHMY2.js} +403 -46
- package/dist/chunk-ROXMHMY2.js.map +1 -0
- package/dist/{chunk-2UUZZJFT.js → chunk-ULHIJK66.js} +228 -177
- package/dist/{chunk-2UUZZJFT.js.map → chunk-ULHIJK66.js.map} +1 -1
- package/dist/{chunk-YGPFYGA6.js → chunk-VKB2CO4Z.js} +838 -503
- package/dist/chunk-VKB2CO4Z.js.map +1 -0
- package/dist/{chunk-3GOZZZYH.js → chunk-VRGWKHDB.js} +238 -301
- package/dist/chunk-VRGWKHDB.js.map +1 -0
- package/dist/{chunk-UCQSRW7Z.js → chunk-XNYQOL3Z.js} +431 -384
- package/dist/chunk-XNYQOL3Z.js.map +1 -0
- package/dist/{chunk-DDM4CCYT.js → chunk-XYXSXPUK.js} +79 -59
- package/dist/chunk-XYXSXPUK.js.map +1 -0
- package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
- package/dist/chunk-ZSAAAMVR.js.map +1 -0
- package/dist/components.d.ts +5 -6
- package/dist/components.js +19 -19
- package/dist/components.js.map +1 -1
- package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
- package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
- package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
- package/dist/hooks.d.ts +20 -15
- package/dist/hooks.js +14 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +17 -15
- package/dist/index.js +86 -81
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +3 -3
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +77 -13
- package/dist/rbac/index.js +12 -9
- package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
- package/dist/types.d.ts +3 -3
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +17 -10
- package/dist/utils.d.ts +8 -8
- package/dist/utils.js +16 -16
- package/docs/README.md +2 -2
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +2 -2
- package/docs/api/classes/Logger.md +1 -1
- package/docs/api/classes/MissingUserContextError.md +2 -2
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/RBACAuditManager.md +2 -2
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +5 -5
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +2 -2
- package/docs/api/classes/SecureSupabaseClient.md +25 -20
- package/docs/api/classes/StorageUtils.md +7 -4
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +1 -1
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AddressFieldProps.md +1 -1
- package/docs/api/interfaces/AddressFieldRef.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/AutocompleteOptions.md +1 -1
- package/docs/api/interfaces/AvatarProps.md +1 -1
- package/docs/api/interfaces/BadgeProps.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- package/docs/api/interfaces/CalendarProps.md +20 -6
- package/docs/api/interfaces/CardProps.md +1 -1
- package/docs/api/interfaces/ColorPalette.md +1 -1
- package/docs/api/interfaces/ColorShade.md +1 -1
- package/docs/api/interfaces/ComplianceResult.md +1 -1
- package/docs/api/interfaces/DataAccessRecord.md +9 -9
- package/docs/api/interfaces/DataRecord.md +1 -1
- package/docs/api/interfaces/DataTableAction.md +1 -1
- package/docs/api/interfaces/DataTableColumn.md +1 -1
- package/docs/api/interfaces/DataTableProps.md +1 -1
- package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
- package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
- package/docs/api/interfaces/DatabaseIssue.md +1 -1
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +1 -1
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +62 -16
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +2 -2
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +26 -12
- package/docs/api/interfaces/FileUploadProps.md +30 -19
- package/docs/api/interfaces/FooterProps.md +1 -1
- package/docs/api/interfaces/FormFieldProps.md +1 -1
- package/docs/api/interfaces/FormProps.md +1 -1
- package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
- package/docs/api/interfaces/InputProps.md +1 -1
- package/docs/api/interfaces/LabelProps.md +1 -1
- package/docs/api/interfaces/LoggerConfig.md +1 -1
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
- package/docs/api/interfaces/NavigationContextType.md +9 -9
- package/docs/api/interfaces/NavigationGuardProps.md +1 -1
- package/docs/api/interfaces/NavigationItem.md +1 -1
- package/docs/api/interfaces/NavigationMenuProps.md +1 -1
- package/docs/api/interfaces/NavigationProviderProps.md +7 -7
- package/docs/api/interfaces/Organisation.md +1 -1
- package/docs/api/interfaces/OrganisationContextType.md +1 -1
- package/docs/api/interfaces/OrganisationMembership.md +1 -1
- package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
- package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
- package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +8 -8
- package/docs/api/interfaces/PagePermissionContextType.md +8 -8
- package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
- package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/ParsedAddress.md +2 -2
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +3 -11
- package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
- package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
- package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
- package/docs/api/interfaces/QuickFix.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
- package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
- package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
- package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
- package/docs/api/interfaces/RBACConfig.md +2 -2
- package/docs/api/interfaces/RBACContext.md +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
- package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
- package/docs/api/interfaces/RBACResult.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
- package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
- package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
- package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
- package/docs/api/interfaces/RBACRolesListParams.md +1 -1
- package/docs/api/interfaces/RBACRolesListResult.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
- package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
- package/docs/api/interfaces/ResourcePermissions.md +1 -1
- package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
- package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
- package/docs/api/interfaces/RoleManagementResult.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +10 -10
- package/docs/api/interfaces/RouteConfig.md +10 -10
- package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +9 -9
- package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +1 -1
- package/docs/api/interfaces/StorageConfig.md +4 -4
- package/docs/api/interfaces/StorageFileInfo.md +7 -7
- package/docs/api/interfaces/StorageFileMetadata.md +25 -14
- package/docs/api/interfaces/StorageListOptions.md +22 -9
- package/docs/api/interfaces/StorageListResult.md +4 -4
- package/docs/api/interfaces/StorageUploadOptions.md +21 -8
- package/docs/api/interfaces/StorageUploadResult.md +6 -6
- package/docs/api/interfaces/StorageUrlOptions.md +19 -6
- package/docs/api/interfaces/StyleImport.md +1 -1
- package/docs/api/interfaces/SwitchProps.md +1 -1
- package/docs/api/interfaces/TabsContentProps.md +1 -1
- package/docs/api/interfaces/TabsListProps.md +1 -1
- package/docs/api/interfaces/TabsProps.md +1 -1
- package/docs/api/interfaces/TabsTriggerProps.md +1 -1
- package/docs/api/interfaces/TextareaProps.md +1 -1
- package/docs/api/interfaces/ToastActionElement.md +1 -1
- package/docs/api/interfaces/ToastProps.md +1 -1
- package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
- package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
- package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +5 -5
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +11 -11
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +165 -106
- package/docs/api-reference/components.md +15 -7
- package/docs/api-reference/providers.md +2 -2
- package/docs/api-reference/rpc-functions.md +1 -0
- package/docs/best-practices/README.md +1 -1
- package/docs/best-practices/deployment.md +8 -8
- package/docs/getting-started/examples/README.md +2 -2
- package/docs/getting-started/installation-guide.md +4 -4
- package/docs/getting-started/quick-start.md +3 -3
- package/docs/migration/MIGRATION_GUIDE.md +3 -3
- package/docs/migration/README.md +18 -0
- package/docs/migration/database-changes-december-2025.md +767 -0
- package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
- package/docs/rbac/compliance/compliance-guide.md +2 -2
- package/docs/rbac/event-based-apps.md +2 -2
- package/docs/rbac/getting-started.md +2 -2
- package/docs/rbac/quick-start.md +2 -2
- package/docs/security/README.md +4 -4
- package/docs/standards/07-rbac-and-rls-standard.md +430 -7
- package/docs/troubleshooting/README.md +2 -2
- package/docs/troubleshooting/migration.md +3 -3
- package/package.json +1 -3
- package/scripts/check-pace-core-compliance.cjs +1 -1
- package/scripts/check-pace-core-compliance.js +1 -1
- package/src/__tests__/fixtures/supabase.ts +301 -0
- package/src/__tests__/public-recipe-view.test.ts +19 -19
- package/src/__tests__/rls-policies.test.ts +210 -74
- package/src/components/AddressField/AddressField.test.tsx +42 -0
- package/src/components/AddressField/AddressField.tsx +71 -60
- package/src/components/AddressField/README.md +7 -6
- package/src/components/Alert/Alert.test.tsx +50 -10
- package/src/components/Alert/Alert.tsx +5 -3
- package/src/components/Avatar/Avatar.test.tsx +95 -43
- package/src/components/Avatar/Avatar.tsx +16 -16
- package/src/components/Button/Button.test.tsx +2 -1
- package/src/components/Button/Button.tsx +3 -3
- package/src/components/Calendar/Calendar.test.tsx +53 -37
- package/src/components/Calendar/Calendar.tsx +409 -82
- package/src/components/Card/Card.test.tsx +7 -4
- package/src/components/Card/Card.tsx +3 -6
- package/src/components/Checkbox/Checkbox.tsx +2 -2
- package/src/components/DataTable/components/ActionButtons.tsx +5 -5
- package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
- package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
- package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
- package/src/components/DataTable/components/DataTableBody.tsx +12 -12
- package/src/components/DataTable/components/DataTableCore.tsx +3 -3
- package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
- package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
- package/src/components/DataTable/components/EditableRow.tsx +2 -2
- package/src/components/DataTable/components/EmptyState.tsx +3 -3
- package/src/components/DataTable/components/GroupHeader.tsx +2 -2
- package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
- package/src/components/DataTable/components/ImportModal.tsx +4 -4
- package/src/components/DataTable/components/LoadingState.tsx +1 -1
- package/src/components/DataTable/components/PaginationControls.tsx +11 -11
- package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
- package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
- package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
- package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
- package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
- package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
- package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
- package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
- package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
- package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
- package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
- package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
- package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
- package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
- package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
- package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
- package/src/components/Dialog/Dialog.tsx +2 -2
- package/src/components/EventSelector/EventSelector.tsx +7 -7
- package/src/components/FileDisplay/FileDisplay.tsx +291 -179
- package/src/components/FileUpload/FileUpload.tsx +7 -4
- package/src/components/Header/Header.test.tsx +28 -0
- package/src/components/Header/Header.tsx +22 -9
- package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
- package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
- package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
- package/src/components/OrganisationSelector/OrganisationSelector.tsx +42 -22
- package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
- package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
- package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
- package/src/components/PaceAppLayout/test-setup.tsx +1 -0
- package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
- package/src/components/Progress/Progress.test.tsx +18 -19
- package/src/components/Progress/Progress.tsx +31 -32
- package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
- package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
- package/src/components/Select/Select.test.tsx +4 -1
- package/src/components/Select/Select.tsx +65 -20
- package/src/components/Switch/Switch.test.tsx +2 -1
- package/src/components/Switch/Switch.tsx +1 -1
- package/src/components/Toast/Toast.tsx +1 -1
- package/src/components/Tooltip/Tooltip.test.tsx +8 -2
- package/src/components/UserMenu/UserMenu.tsx +3 -3
- package/src/eslint-rules/pace-core-compliance.cjs +0 -2
- package/src/eslint-rules/pace-core-compliance.js +0 -2
- package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
- package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
- package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
- package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
- package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
- package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -1
- package/src/hooks/__tests__/usePublicEvent.test.ts +608 -0
- package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +67 -24
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEvent.ts +10 -10
- package/src/hooks/public/usePublicFileDisplay.ts +173 -87
- package/src/hooks/useAppConfig.ts +24 -5
- package/src/hooks/useFileDisplay.ts +298 -36
- package/src/hooks/useFileReference.ts +56 -11
- package/src/hooks/useFileUrl.ts +1 -1
- package/src/hooks/useInactivityTracker.ts +16 -7
- package/src/hooks/usePermissionCache.test.ts +85 -8
- package/src/hooks/useQueryCache.ts +27 -6
- package/src/hooks/useSecureDataAccess.test.ts +87 -42
- package/src/hooks/useSecureDataAccess.ts +95 -48
- package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
- package/src/providers/services/EventServiceProvider.tsx +37 -17
- package/src/providers/services/InactivityServiceProvider.tsx +4 -4
- package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
- package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
- package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
- package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
- package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
- package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
- package/src/rbac/api.ts +240 -36
- package/src/rbac/cache-invalidation.ts +21 -7
- package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
- package/src/rbac/components/NavigationGuard.tsx +23 -63
- package/src/rbac/components/NavigationProvider.test.tsx +52 -23
- package/src/rbac/components/NavigationProvider.tsx +13 -11
- package/src/rbac/components/PagePermissionGuard.tsx +77 -203
- package/src/rbac/components/PagePermissionProvider.tsx +13 -11
- package/src/rbac/components/PermissionEnforcer.tsx +24 -62
- package/src/rbac/components/RoleBasedRouter.tsx +14 -12
- package/src/rbac/components/SecureDataProvider.tsx +13 -11
- package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
- package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
- package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
- package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
- package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
- package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
- package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
- package/src/rbac/engine.ts +4 -2
- package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
- package/src/rbac/hooks/index.ts +3 -0
- package/src/rbac/hooks/useCan.test.ts +101 -53
- package/src/rbac/hooks/usePermissions.ts +108 -41
- package/src/rbac/hooks/useRBAC.test.ts +11 -3
- package/src/rbac/hooks/useRBAC.ts +83 -40
- package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
- package/src/rbac/hooks/useResolvedScope.ts +128 -70
- package/src/rbac/hooks/useSecureSupabase.ts +36 -19
- package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
- package/src/rbac/request-deduplication.ts +1 -1
- package/src/rbac/secureClient.ts +72 -12
- package/src/rbac/security.ts +29 -23
- package/src/rbac/types.ts +10 -0
- package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
- package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
- package/src/rbac/utils/__tests__/eventContext.test.ts +8 -3
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +74 -12
- package/src/rbac/utils/contextValidator.ts +288 -0
- package/src/rbac/utils/eventContext.ts +52 -3
- package/src/services/AuthService.ts +37 -8
- package/src/services/EventService.ts +165 -21
- package/src/services/OrganisationService.ts +125 -137
- package/src/services/__tests__/EventService.test.ts +26 -21
- package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
- package/src/services/__tests__/OrganisationService.test.ts +218 -86
- package/src/types/database.generated.ts +166 -201
- package/src/types/file-reference.ts +13 -10
- package/src/types/supabase.ts +2 -2
- package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
- package/src/utils/app/appNameResolver.test.ts +346 -73
- package/src/utils/context/superAdminOverride.ts +58 -0
- package/src/utils/file-reference/index.ts +65 -37
- package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
- package/src/utils/google-places/googlePlacesUtils.ts +1 -1
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
- package/src/utils/google-places/types.ts +1 -1
- package/src/utils/request-deduplication.ts +4 -4
- package/src/utils/security/secureDataAccess.test.ts +1 -1
- package/src/utils/security/secureDataAccess.ts +7 -4
- package/src/utils/storage/README.md +1 -1
- package/src/utils/storage/helpers.test.ts +1 -1
- package/src/utils/storage/helpers.ts +38 -19
- package/src/utils/storage/types.ts +15 -8
- package/src/utils/validation/__tests__/csrf.test.ts +105 -0
- package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
- package/src/vite-env.d.ts +2 -2
- package/dist/chunk-3GOZZZYH.js.map +0 -1
- package/dist/chunk-DDM4CCYT.js.map +0 -1
- package/dist/chunk-E7UAOUMY.js +0 -75
- package/dist/chunk-E7UAOUMY.js.map +0 -1
- package/dist/chunk-F2IMUDXZ.js.map +0 -1
- package/dist/chunk-HEHYGYOX.js.map +0 -1
- package/dist/chunk-IM4QE42D.js.map +0 -1
- package/dist/chunk-MX64ZF6I.js.map +0 -1
- package/dist/chunk-SAUPYVLF.js.map +0 -1
- package/dist/chunk-THRPYOFK.js.map +0 -1
- package/dist/chunk-UCQSRW7Z.js.map +0 -1
- package/dist/chunk-VGZZXKBR.js.map +0 -1
- package/dist/chunk-YGPFYGA6.js.map +0 -1
- package/dist/chunk-YHCN776L.js.map +0 -1
- /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-WKRZD47S.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
- /package/dist/{api-YP7XD5L6.js.map → api-IHKALJZD.js.map} +0 -0
- /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
|
@@ -31,6 +31,11 @@ vi.mock('../../utils/eventContext', () => ({
|
|
|
31
31
|
createScopeFromEvent: vi.fn()
|
|
32
32
|
}));
|
|
33
33
|
|
|
34
|
+
// Mock useResolvedScope hook
|
|
35
|
+
vi.mock('../../hooks/useResolvedScope', () => ({
|
|
36
|
+
useResolvedScope: vi.fn()
|
|
37
|
+
}));
|
|
38
|
+
|
|
34
39
|
// Mock the Logger module
|
|
35
40
|
vi.mock('../../../utils/core/logger', () => {
|
|
36
41
|
const mockLoggerInstance = {
|
|
@@ -48,6 +53,7 @@ import { createLogger } from '../../../utils/core/logger';
|
|
|
48
53
|
const getMockLogger = () => createLogger('test');
|
|
49
54
|
|
|
50
55
|
import { createScopeFromEvent } from '../../utils/eventContext';
|
|
56
|
+
import { useResolvedScope } from '../../hooks/useResolvedScope';
|
|
51
57
|
|
|
52
58
|
// Mock data
|
|
53
59
|
const mockUser = {
|
|
@@ -80,6 +86,7 @@ const TestLoading = () => (
|
|
|
80
86
|
describe('PermissionEnforcer Component', () => {
|
|
81
87
|
const mockUseMultiplePermissions = vi.mocked(useMultiplePermissions);
|
|
82
88
|
const mockCreateScopeFromEvent = vi.mocked(createScopeFromEvent);
|
|
89
|
+
const mockUseResolvedScope = vi.mocked(useResolvedScope);
|
|
83
90
|
|
|
84
91
|
beforeEach(() => {
|
|
85
92
|
vi.clearAllMocks();
|
|
@@ -92,6 +99,17 @@ describe('PermissionEnforcer Component', () => {
|
|
|
92
99
|
supabase: {} as any
|
|
93
100
|
});
|
|
94
101
|
|
|
102
|
+
// Mock useResolvedScope to return resolved scope immediately
|
|
103
|
+
mockUseResolvedScope.mockReturnValue({
|
|
104
|
+
resolvedScope: {
|
|
105
|
+
organisationId: 'org-123',
|
|
106
|
+
eventId: 'event-123',
|
|
107
|
+
appId: 'app-123'
|
|
108
|
+
},
|
|
109
|
+
isLoading: false,
|
|
110
|
+
error: null
|
|
111
|
+
});
|
|
112
|
+
|
|
95
113
|
mockUseMultiplePermissions.mockReturnValue({
|
|
96
114
|
results: {
|
|
97
115
|
'read:events': true,
|
|
@@ -243,10 +261,11 @@ describe('PermissionEnforcer Component', () => {
|
|
|
243
261
|
|
|
244
262
|
expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
|
|
245
263
|
'user-123',
|
|
246
|
-
|
|
264
|
+
{
|
|
247
265
|
organisationId: 'org-123',
|
|
248
|
-
eventId: 'event-123'
|
|
249
|
-
|
|
266
|
+
eventId: 'event-123',
|
|
267
|
+
appId: 'app-123'
|
|
268
|
+
},
|
|
250
269
|
['read:events'], // singlePermission only includes read:events
|
|
251
270
|
true
|
|
252
271
|
);
|
|
@@ -277,10 +296,11 @@ describe('PermissionEnforcer Component', () => {
|
|
|
277
296
|
// Should check all permissions when requireAll=true
|
|
278
297
|
expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
|
|
279
298
|
'user-123',
|
|
280
|
-
|
|
299
|
+
{
|
|
281
300
|
organisationId: 'org-123',
|
|
282
|
-
eventId: 'event-123'
|
|
283
|
-
|
|
301
|
+
eventId: 'event-123',
|
|
302
|
+
appId: 'app-123'
|
|
303
|
+
},
|
|
284
304
|
['read:events', 'update:events'],
|
|
285
305
|
true
|
|
286
306
|
);
|
|
@@ -393,16 +413,18 @@ describe('PermissionEnforcer Component', () => {
|
|
|
393
413
|
|
|
394
414
|
expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
|
|
395
415
|
'user-123',
|
|
396
|
-
|
|
416
|
+
{
|
|
397
417
|
organisationId: 'org-123',
|
|
398
|
-
eventId: 'event-123'
|
|
399
|
-
|
|
418
|
+
eventId: 'event-123',
|
|
419
|
+
appId: 'app-123'
|
|
420
|
+
},
|
|
400
421
|
['read:events', 'update:events'], // mockPermissions includes both
|
|
401
422
|
true
|
|
402
423
|
);
|
|
403
424
|
});
|
|
404
425
|
|
|
405
|
-
it('resolves scope from organisation only', async () => {
|
|
426
|
+
it('resolves scope from organisation only (org-required app)', async () => {
|
|
427
|
+
// For org-required apps, organisation is primary context, event is optional
|
|
406
428
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
407
429
|
user: mockUser,
|
|
408
430
|
selectedOrganisation: { id: 'org-123' },
|
|
@@ -410,6 +432,16 @@ describe('PermissionEnforcer Component', () => {
|
|
|
410
432
|
supabase: {} as any
|
|
411
433
|
});
|
|
412
434
|
|
|
435
|
+
mockUseResolvedScope.mockReturnValue({
|
|
436
|
+
resolvedScope: {
|
|
437
|
+
organisationId: 'org-123',
|
|
438
|
+
eventId: undefined,
|
|
439
|
+
appId: 'app-123'
|
|
440
|
+
},
|
|
441
|
+
isLoading: false,
|
|
442
|
+
error: null
|
|
443
|
+
});
|
|
444
|
+
|
|
413
445
|
mockUseMultiplePermissions.mockReturnValue({
|
|
414
446
|
results: { 'read:events': true } as Record<string, boolean>,
|
|
415
447
|
isLoading: false,
|
|
@@ -432,27 +464,33 @@ describe('PermissionEnforcer Component', () => {
|
|
|
432
464
|
|
|
433
465
|
expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
|
|
434
466
|
'user-123',
|
|
435
|
-
|
|
467
|
+
{
|
|
436
468
|
organisationId: 'org-123',
|
|
437
|
-
eventId: undefined
|
|
438
|
-
|
|
469
|
+
eventId: undefined,
|
|
470
|
+
appId: 'app-123'
|
|
471
|
+
},
|
|
439
472
|
['read:events', 'update:events'], // mockPermissions includes both
|
|
440
473
|
true
|
|
441
474
|
);
|
|
442
475
|
});
|
|
443
476
|
|
|
444
|
-
it('resolves scope from event context when organisation not available', async () => {
|
|
477
|
+
it('resolves scope from event context when organisation not available (event-required app)', async () => {
|
|
478
|
+
// For event-required apps, selectedOrganisation is null, org is derived from event
|
|
445
479
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
446
480
|
user: mockUser,
|
|
447
|
-
selectedOrganisation: null,
|
|
481
|
+
selectedOrganisation: null, // Not available for event-required apps
|
|
448
482
|
selectedEvent: { event_id: 'event-123' },
|
|
449
483
|
supabase: {} as any
|
|
450
484
|
});
|
|
451
485
|
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
486
|
+
mockUseResolvedScope.mockReturnValue({
|
|
487
|
+
resolvedScope: {
|
|
488
|
+
organisationId: 'resolved-org',
|
|
489
|
+
eventId: 'event-123',
|
|
490
|
+
appId: 'resolved-app'
|
|
491
|
+
},
|
|
492
|
+
isLoading: false,
|
|
493
|
+
error: null
|
|
456
494
|
});
|
|
457
495
|
|
|
458
496
|
mockUseMultiplePermissions.mockReturnValue({
|
|
@@ -475,13 +513,13 @@ describe('PermissionEnforcer Component', () => {
|
|
|
475
513
|
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
476
514
|
}, { interval: 10 });
|
|
477
515
|
|
|
478
|
-
expect(mockCreateScopeFromEvent).toHaveBeenCalledWith({}, 'event-123');
|
|
479
516
|
expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
|
|
480
517
|
'user-123',
|
|
481
|
-
|
|
518
|
+
{
|
|
482
519
|
organisationId: 'resolved-org',
|
|
483
|
-
eventId: 'event-123'
|
|
484
|
-
|
|
520
|
+
eventId: 'event-123',
|
|
521
|
+
appId: 'resolved-app'
|
|
522
|
+
},
|
|
485
523
|
['read:events', 'update:events'], // mockPermissions includes both
|
|
486
524
|
true
|
|
487
525
|
);
|
|
@@ -496,7 +534,11 @@ describe('PermissionEnforcer Component', () => {
|
|
|
496
534
|
});
|
|
497
535
|
|
|
498
536
|
const error = new Error('Could not resolve organisation from event');
|
|
499
|
-
|
|
537
|
+
mockUseResolvedScope.mockReturnValue({
|
|
538
|
+
resolvedScope: null,
|
|
539
|
+
isLoading: false,
|
|
540
|
+
error
|
|
541
|
+
});
|
|
500
542
|
|
|
501
543
|
render(
|
|
502
544
|
<PermissionEnforcer
|
|
@@ -521,6 +563,12 @@ describe('PermissionEnforcer Component', () => {
|
|
|
521
563
|
supabase: null
|
|
522
564
|
});
|
|
523
565
|
|
|
566
|
+
mockUseResolvedScope.mockReturnValue({
|
|
567
|
+
resolvedScope: null,
|
|
568
|
+
isLoading: true,
|
|
569
|
+
error: null
|
|
570
|
+
});
|
|
571
|
+
|
|
524
572
|
render(
|
|
525
573
|
<PermissionEnforcer
|
|
526
574
|
permissions={mockPermissions}
|
|
@@ -531,9 +579,7 @@ describe('PermissionEnforcer Component', () => {
|
|
|
531
579
|
</PermissionEnforcer>
|
|
532
580
|
);
|
|
533
581
|
|
|
534
|
-
|
|
535
|
-
expect(screen.getByTestId('test-component')).toBeInTheDocument();
|
|
536
|
-
}, { interval: 10 });
|
|
582
|
+
expect(screen.getByText('Checking permissions...')).toBeInTheDocument();
|
|
537
583
|
});
|
|
538
584
|
});
|
|
539
585
|
|
|
@@ -798,10 +844,11 @@ describe('PermissionEnforcer Component', () => {
|
|
|
798
844
|
|
|
799
845
|
expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
|
|
800
846
|
'',
|
|
801
|
-
|
|
847
|
+
{
|
|
802
848
|
organisationId: 'org-123',
|
|
803
|
-
eventId: 'event-123'
|
|
804
|
-
|
|
849
|
+
eventId: 'event-123',
|
|
850
|
+
appId: 'app-123'
|
|
851
|
+
},
|
|
805
852
|
['read:events', 'update:events'], // mockPermissions includes both
|
|
806
853
|
true
|
|
807
854
|
);
|
|
@@ -27,6 +27,12 @@ vi.mock('../../../providers/services/UnifiedAuthProvider', () => ({
|
|
|
27
27
|
UnifiedAuthProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
|
|
28
28
|
}));
|
|
29
29
|
|
|
30
|
+
// Mock useResolvedScope
|
|
31
|
+
const mockUseResolvedScopeFn = vi.fn();
|
|
32
|
+
vi.mock('../../hooks/useResolvedScope', () => ({
|
|
33
|
+
useResolvedScope: () => mockUseResolvedScopeFn(),
|
|
34
|
+
}));
|
|
35
|
+
|
|
30
36
|
// Mock React Router
|
|
31
37
|
vi.mock('react-router-dom', async () => {
|
|
32
38
|
const actual = await vi.importActual('react-router-dom');
|
|
@@ -49,7 +55,7 @@ const mockUser = {
|
|
|
49
55
|
const mockScope = {
|
|
50
56
|
organisationId: 'org-123',
|
|
51
57
|
eventId: 'event-123',
|
|
52
|
-
appId:
|
|
58
|
+
appId: undefined // Most tests expect undefined
|
|
53
59
|
};
|
|
54
60
|
|
|
55
61
|
const mockRoutes = [
|
|
@@ -101,7 +107,20 @@ describe('RoleBasedRouter Component', () => {
|
|
|
101
107
|
mockUseUnifiedAuthFn.mockReturnValue({
|
|
102
108
|
user: mockUser,
|
|
103
109
|
selectedOrganisation: { id: 'org-123' },
|
|
104
|
-
selectedEvent: { event_id: 'event-123' }
|
|
110
|
+
selectedEvent: { event_id: 'event-123' },
|
|
111
|
+
supabase: {} as any,
|
|
112
|
+
});
|
|
113
|
+
|
|
114
|
+
// Mock useResolvedScope to return resolved scope
|
|
115
|
+
// Note: appId is undefined in some tests, so we'll set it conditionally
|
|
116
|
+
mockUseResolvedScopeFn.mockReturnValue({
|
|
117
|
+
resolvedScope: {
|
|
118
|
+
organisationId: 'org-123',
|
|
119
|
+
eventId: 'event-123',
|
|
120
|
+
appId: undefined, // Default to undefined for most tests
|
|
121
|
+
},
|
|
122
|
+
isLoading: false,
|
|
123
|
+
error: null,
|
|
105
124
|
});
|
|
106
125
|
|
|
107
126
|
mockUseLocation.mockReturnValue({
|
|
@@ -233,11 +252,16 @@ describe('RoleBasedRouter Component', () => {
|
|
|
233
252
|
expect.objectContaining({
|
|
234
253
|
organisationId: 'org-123',
|
|
235
254
|
eventId: 'event-123',
|
|
236
|
-
appId: undefined
|
|
237
255
|
}),
|
|
238
256
|
'read:dashboard',
|
|
239
257
|
'dashboard'
|
|
240
258
|
);
|
|
259
|
+
// Check that appId is either undefined or matches expected value
|
|
260
|
+
const call = mockUseCan.mock.calls.find(c => c[0] === 'user-123' && c[2] === 'read:dashboard');
|
|
261
|
+
expect(call).toBeDefined();
|
|
262
|
+
if (call) {
|
|
263
|
+
expect(call[1].appId).toBeUndefined();
|
|
264
|
+
}
|
|
241
265
|
});
|
|
242
266
|
|
|
243
267
|
it('denies access to routes without permissions', async () => {
|
|
@@ -639,11 +663,16 @@ describe('RoleBasedRouter Component', () => {
|
|
|
639
663
|
expect.objectContaining({
|
|
640
664
|
organisationId: 'org-123',
|
|
641
665
|
eventId: 'event-123',
|
|
642
|
-
appId: undefined
|
|
643
666
|
}),
|
|
644
667
|
'read:dashboard',
|
|
645
668
|
'dashboard'
|
|
646
669
|
);
|
|
670
|
+
// Check that appId is either undefined or matches expected value
|
|
671
|
+
const call = mockUseCan.mock.calls.find(c => c[0] === '' && c[2] === 'read:dashboard');
|
|
672
|
+
expect(call).toBeDefined();
|
|
673
|
+
if (call) {
|
|
674
|
+
expect(call[1].appId).toBeUndefined();
|
|
675
|
+
}
|
|
647
676
|
});
|
|
648
677
|
|
|
649
678
|
it('handles missing organisation context', async () => {
|
|
@@ -727,12 +756,17 @@ describe('RoleBasedRouter Component', () => {
|
|
|
727
756
|
expect.objectContaining({
|
|
728
757
|
organisationId: 'org-123',
|
|
729
758
|
eventId: 'event-123',
|
|
730
|
-
appId: undefined
|
|
731
759
|
}),
|
|
732
760
|
'admin:system',
|
|
733
761
|
'admin'
|
|
734
762
|
);
|
|
735
763
|
}, { interval: 10 });
|
|
764
|
+
// Check that appId is either undefined or matches expected value
|
|
765
|
+
const call = mockUseCan.mock.calls.find(c => c[0] === 'user-123' && c[2] === 'admin:system');
|
|
766
|
+
expect(call).toBeDefined();
|
|
767
|
+
if (call) {
|
|
768
|
+
expect(call[1].appId).toBeUndefined();
|
|
769
|
+
}
|
|
736
770
|
});
|
|
737
771
|
});
|
|
738
772
|
});
|
|
@@ -61,6 +61,12 @@ vi.mock('../../../hooks/useSecureDataAccess', () => ({
|
|
|
61
61
|
}))
|
|
62
62
|
}));
|
|
63
63
|
|
|
64
|
+
// Mock useResolvedScope
|
|
65
|
+
const mockUseResolvedScopeFn = vi.fn();
|
|
66
|
+
vi.mock('../../hooks/useResolvedScope', () => ({
|
|
67
|
+
useResolvedScope: () => mockUseResolvedScopeFn(),
|
|
68
|
+
}));
|
|
69
|
+
|
|
64
70
|
// Test data
|
|
65
71
|
const mockUser = {
|
|
66
72
|
user: {
|
|
@@ -147,7 +153,18 @@ describe('SecureDataProvider', () => {
|
|
|
147
153
|
beforeEach(() => {
|
|
148
154
|
vi.clearAllMocks();
|
|
149
155
|
|
|
150
|
-
mockUseUnifiedAuthFn.mockReturnValue(
|
|
156
|
+
mockUseUnifiedAuthFn.mockReturnValue({
|
|
157
|
+
...mockUser,
|
|
158
|
+
supabase: {} as any,
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
// Mock useResolvedScope to return resolved scope
|
|
162
|
+
mockUseResolvedScopeFn.mockReturnValue({
|
|
163
|
+
resolvedScope: mockScope,
|
|
164
|
+
isLoading: false,
|
|
165
|
+
error: null,
|
|
166
|
+
});
|
|
167
|
+
|
|
151
168
|
mockValidateContext.mockImplementation(() => {});
|
|
152
169
|
});
|
|
153
170
|
|
|
@@ -278,8 +295,22 @@ describe('SecureDataProvider', () => {
|
|
|
278
295
|
expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
|
|
279
296
|
});
|
|
280
297
|
|
|
281
|
-
it('should deny data access when organisation context is missing', () => {
|
|
282
|
-
|
|
298
|
+
it('should deny data access when organisation context is missing (org-required app)', () => {
|
|
299
|
+
// For org-required apps, selectedOrganisation is required
|
|
300
|
+
// For event-required apps, selectedOrganisation is null and org is derived from event
|
|
301
|
+
mockUseUnifiedAuthFn.mockReturnValue({
|
|
302
|
+
...mockUser,
|
|
303
|
+
selectedOrganisation: null,
|
|
304
|
+
selectedEvent: null, // No event either, so no context available
|
|
305
|
+
supabase: {} as any,
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
// Mock useResolvedScope to return null scope when no context available
|
|
309
|
+
mockUseResolvedScopeFn.mockReturnValue({
|
|
310
|
+
resolvedScope: null,
|
|
311
|
+
isLoading: false,
|
|
312
|
+
error: null,
|
|
313
|
+
});
|
|
283
314
|
|
|
284
315
|
renderWithProviders(
|
|
285
316
|
<TestWrapper>
|
|
@@ -411,7 +442,19 @@ describe('SecureDataProvider', () => {
|
|
|
411
442
|
});
|
|
412
443
|
|
|
413
444
|
it('should handle missing organisation context gracefully', () => {
|
|
414
|
-
mockUseUnifiedAuthFn.mockReturnValue({
|
|
445
|
+
mockUseUnifiedAuthFn.mockReturnValue({
|
|
446
|
+
...mockUser,
|
|
447
|
+
selectedOrganisation: null,
|
|
448
|
+
selectedEvent: null, // No event either
|
|
449
|
+
supabase: {} as any,
|
|
450
|
+
});
|
|
451
|
+
|
|
452
|
+
// Mock useResolvedScope to return null scope when no context available
|
|
453
|
+
mockUseResolvedScopeFn.mockReturnValue({
|
|
454
|
+
resolvedScope: null,
|
|
455
|
+
isLoading: false,
|
|
456
|
+
error: null,
|
|
457
|
+
});
|
|
415
458
|
|
|
416
459
|
renderWithProviders(
|
|
417
460
|
<TestWrapper>
|
package/src/rbac/engine.ts
CHANGED
|
@@ -296,7 +296,7 @@ export class RBACEngine {
|
|
|
296
296
|
|
|
297
297
|
// Check organisation role
|
|
298
298
|
if (scope.organisationId) {
|
|
299
|
-
const { data:
|
|
299
|
+
const { data: orgRoles } = await this.supabase
|
|
300
300
|
.from('rbac_organisation_roles')
|
|
301
301
|
.select('role')
|
|
302
302
|
.eq('user_id', userId)
|
|
@@ -305,7 +305,9 @@ export class RBACEngine {
|
|
|
305
305
|
.is('revoked_at', null)
|
|
306
306
|
.lte('valid_from', now)
|
|
307
307
|
.or(`valid_to.is.null,valid_to.gte.${now}`)
|
|
308
|
-
.
|
|
308
|
+
.limit(1) as { data: Array<{ role: string }> | null; error: any };
|
|
309
|
+
|
|
310
|
+
const orgRole = orgRoles?.[0];
|
|
309
311
|
|
|
310
312
|
if (orgRole?.role === 'org_admin') {
|
|
311
313
|
rbacCache.set(cacheKey, 'admin', 60000);
|