@jmruthers/pace-core 0.5.189 → 0.5.190
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-GUFUNZ3N.js → DataTable-ON3IXISJ.js} +8 -8
- package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-C4uxosp6.d.ts} +83 -24
- package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
- package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-X5NXANVI.js} +4 -2
- package/dist/{api-YP7XD5L6.js → api-I6UCQ5S6.js} +4 -2
- package/dist/{chunk-DDM4CCYT.js → chunk-4QYC5L4K.js} +60 -35
- package/dist/chunk-4QYC5L4K.js.map +1 -0
- package/dist/{chunk-IM4QE42D.js → chunk-73HSNNOQ.js} +141 -326
- package/dist/chunk-73HSNNOQ.js.map +1 -0
- package/dist/{chunk-YHCN776L.js → chunk-DZWK57KZ.js} +2 -75
- package/dist/chunk-DZWK57KZ.js.map +1 -0
- package/dist/{chunk-3GOZZZYH.js → chunk-HQVPB5MZ.js} +238 -301
- package/dist/chunk-HQVPB5MZ.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-VGZZXKBR.js → chunk-J2XXC7R5.js} +280 -52
- package/dist/chunk-J2XXC7R5.js.map +1 -0
- package/dist/{chunk-UCQSRW7Z.js → chunk-NIU6J6OX.js} +425 -378
- package/dist/chunk-NIU6J6OX.js.map +1 -0
- package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
- package/dist/{chunk-HEHYGYOX.js → chunk-RUYZKXOD.js} +401 -46
- package/dist/chunk-RUYZKXOD.js.map +1 -0
- package/dist/{chunk-2UUZZJFT.js → chunk-SDMHPX3X.js} +176 -160
- package/dist/{chunk-2UUZZJFT.js.map → chunk-SDMHPX3X.js.map} +1 -1
- package/dist/{chunk-MX64ZF6I.js → chunk-STYK4OH2.js} +11 -11
- package/dist/chunk-STYK4OH2.js.map +1 -0
- package/dist/{chunk-YGPFYGA6.js → chunk-VVBAW5A5.js} +822 -498
- package/dist/chunk-VVBAW5A5.js.map +1 -0
- package/dist/chunk-Y4BUBBHD.js +614 -0
- package/dist/chunk-Y4BUBBHD.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 +3 -4
- package/dist/components.js +19 -19
- package/dist/components.js.map +1 -1
- 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 +10 -5
- package/dist/hooks.js +14 -8
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +13 -11
- package/dist/index.js +79 -69
- 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 +76 -12
- package/dist/rbac/index.js +12 -9
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-DxIDS4bC.d.ts} +16 -9
- 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 +1 -1
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +4 -4
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +2 -2
- package/docs/api/classes/SecureSupabaseClient.md +21 -16
- 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 +1 -1
- 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 +1 -1
- 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 +1 -1
- package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
- package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
- package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
- package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
- package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
- package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
- package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
- package/docs/api/interfaces/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 +151 -92
- 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/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 +9 -9
- package/src/__tests__/rls-policies.test.ts +197 -61
- package/src/components/AddressField/AddressField.test.tsx +42 -0
- package/src/components/AddressField/AddressField.tsx +71 -60
- package/src/components/AddressField/README.md +1 -0
- 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 +8 -8
- 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.tsx +5 -5
- 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.unit.test.ts → usePublicEvent.test.ts} +28 -1
- package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
- package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +58 -16
- package/src/hooks/index.ts +1 -1
- package/src/hooks/public/usePublicEvent.ts +2 -2
- package/src/hooks/public/usePublicFileDisplay.ts +173 -87
- package/src/hooks/useAppConfig.ts +24 -5
- package/src/hooks/useFileDisplay.ts +297 -34
- 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 +21 -0
- package/src/hooks/useSecureDataAccess.test.ts +80 -35
- package/src/hooks/useSecureDataAccess.ts +80 -37
- 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 +6 -1
- package/src/rbac/utils/contextValidator.ts +288 -0
- package/src/rbac/utils/eventContext.ts +48 -2
- package/src/services/EventService.ts +165 -21
- package/src/services/OrganisationService.ts +37 -2
- package/src/services/__tests__/EventService.test.ts +26 -21
- package/src/types/file-reference.ts +13 -10
- package/src/utils/app/appNameResolver.test.ts +346 -73
- package/src/utils/context/superAdminOverride.ts +58 -0
- package/src/utils/file-reference/index.ts +61 -33
- package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
- package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
- 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/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
- package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
- package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -703
- package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
- package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
- /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-ON3IXISJ.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-X5NXANVI.js.map} +0 -0
- /package/dist/{api-YP7XD5L6.js.map → api-I6UCQ5S6.js.map} +0 -0
- /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
|
@@ -96,7 +96,8 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
96
96
|
|
|
97
97
|
// Only update the stable scope if the resolved scope has actually changed
|
|
98
98
|
// This prevents unnecessary re-renders while maintaining up-to-date permission checks
|
|
99
|
-
|
|
99
|
+
// Allow scope updates even when organisationId is undefined (for users without orgs, like profile pages)
|
|
100
|
+
if (rawResolvedScope) {
|
|
100
101
|
const newScope = {
|
|
101
102
|
organisationId: rawResolvedScope.organisationId,
|
|
102
103
|
appId: rawResolvedScope.appId,
|
|
@@ -113,8 +114,8 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
113
114
|
eventId: newScope.eventId
|
|
114
115
|
};
|
|
115
116
|
}
|
|
116
|
-
} else if (!rawResolvedScope) {
|
|
117
|
-
// Reset to empty scope when no resolved scope (e.g., user logged out)
|
|
117
|
+
} else if (!rawResolvedScope && !scopeLoading) {
|
|
118
|
+
// Reset to empty scope when no resolved scope and resolution is complete (e.g., user logged out)
|
|
118
119
|
stableScopeRef.current = { organisationId: undefined, appId: undefined, eventId: undefined };
|
|
119
120
|
}
|
|
120
121
|
|
|
@@ -123,10 +124,28 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
123
124
|
/**
|
|
124
125
|
* Effective scope for permission checks.
|
|
125
126
|
*
|
|
126
|
-
*
|
|
127
|
-
* This
|
|
127
|
+
* Use the resolved scope once scope resolution is complete, even if organisationId is undefined.
|
|
128
|
+
* This allows permission checks for users without organisations (e.g., profile pages).
|
|
129
|
+
* The database function rbac_check_permission_simplified can handle NULL organisation_id.
|
|
130
|
+
*
|
|
131
|
+
* IMPORTANT: When using pageName (not pageId), we MUST wait for appId to be resolved,
|
|
132
|
+
* because the RPC function needs appId to resolve the pageName to a pageId UUID.
|
|
133
|
+
* If we have a pageId (UUID), we can proceed even without appId.
|
|
134
|
+
*
|
|
135
|
+
* The key issue: When pageName is used without appId, the RPC function cannot resolve
|
|
136
|
+
* the pageName to a pageId, which causes permission checks to fail initially, showing
|
|
137
|
+
* "Access Denied" before the scope resolves and permissions are re-checked.
|
|
128
138
|
*/
|
|
129
|
-
const
|
|
139
|
+
const isPageName = !pageId && !!pageName; // We're using pageName, not a UUID pageId
|
|
140
|
+
const needsAppIdForResolution = isPageName; // Only need appId if we're resolving a pageName
|
|
141
|
+
|
|
142
|
+
// Wait for scope resolution if:
|
|
143
|
+
// 1. Scope is still loading, OR
|
|
144
|
+
// 2. We're using pageName and don't have appId yet (needed to resolve pageName to pageId)
|
|
145
|
+
// This prevents premature permission checks that would fail and show "Access Denied"
|
|
146
|
+
const shouldWaitForScope = scopeLoading || (needsAppIdForResolution && !stableScope.appId);
|
|
147
|
+
|
|
148
|
+
const effectiveScope = (!shouldWaitForScope) ? stableScope : null;
|
|
130
149
|
|
|
131
150
|
// Always call hooks with consistent parameters to avoid React hooks order violations
|
|
132
151
|
const userId = user?.id || '';
|
|
@@ -136,7 +155,9 @@ export function useDataTablePermissions<TData extends DataRecord>(
|
|
|
136
155
|
const deletePermission = `delete:page.${effectivePageId}` as unknown as Permission;
|
|
137
156
|
|
|
138
157
|
// Always use a consistent scope object to prevent hooks order violations
|
|
139
|
-
// When scope is loading or
|
|
158
|
+
// When scope is loading or we need appId for pageName resolution, use empty scope which will cause useCan to wait
|
|
159
|
+
// When scope resolution is complete (even with undefined organisationId), use the resolved scope
|
|
160
|
+
// This allows permission checks for users without organisations (e.g., profile pages)
|
|
140
161
|
const consistentScope = effectiveScope || { organisationId: undefined, eventId: undefined, appId: undefined };
|
|
141
162
|
|
|
142
163
|
const permissions = {
|
|
@@ -281,10 +281,39 @@ describe('[unit] getRowDepth', () => {
|
|
|
281
281
|
|
|
282
282
|
const childDepth = getRowDepth(nestedData[1], nestedData);
|
|
283
283
|
const grandchildDepth = getRowDepth(nestedData[2], nestedData);
|
|
284
|
-
|
|
284
|
+
|
|
285
285
|
expect(childDepth).toBe(1);
|
|
286
286
|
expect(grandchildDepth).toBe(2);
|
|
287
287
|
});
|
|
288
|
+
|
|
289
|
+
it('caps traversal at the provided maximum depth', () => {
|
|
290
|
+
const deepHierarchy = [
|
|
291
|
+
{ id: 'root', name: 'Root', value: 0, isParent: true },
|
|
292
|
+
...Array.from({ length: 120 }, (_, index) => ({
|
|
293
|
+
id: `child-${index}`,
|
|
294
|
+
name: `Child ${index}`,
|
|
295
|
+
value: index,
|
|
296
|
+
parentId: index === 0 ? 'root' : `child-${index - 1}`,
|
|
297
|
+
isParent: false,
|
|
298
|
+
})),
|
|
299
|
+
];
|
|
300
|
+
|
|
301
|
+
const deepestChild = deepHierarchy[deepHierarchy.length - 1];
|
|
302
|
+
const depth = getRowDepth(deepestChild, deepHierarchy, 50);
|
|
303
|
+
|
|
304
|
+
expect(depth).toBe(50);
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
it('breaks traversal on circular references', () => {
|
|
308
|
+
const cyclicHierarchy = [
|
|
309
|
+
{ id: 'node1', name: 'Node 1', value: 1, parentId: 'node2', isParent: false },
|
|
310
|
+
{ id: 'node2', name: 'Node 2', value: 2, parentId: 'node1', isParent: false }
|
|
311
|
+
];
|
|
312
|
+
|
|
313
|
+
const depth = getRowDepth(cyclicHierarchy[0], cyclicHierarchy, 10);
|
|
314
|
+
|
|
315
|
+
expect(depth).toBe(2);
|
|
316
|
+
});
|
|
288
317
|
});
|
|
289
318
|
|
|
290
319
|
describe('[unit] shouldShowColumnForRow', () => {
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
8
|
import type { HierarchicalDataRow, DataTableColumn, DataRecord } from '../types';
|
|
9
|
+
import { createLogger } from '../../../utils/core/logger';
|
|
9
10
|
|
|
10
11
|
/**
|
|
11
12
|
* Validates that data conforms to hierarchical structure
|
|
@@ -83,7 +84,9 @@ export function groupHierarchicalData<TData extends HierarchicalDataRow>(
|
|
|
83
84
|
* Optimized depth cache to avoid recalculating depth for the same row
|
|
84
85
|
* This prevents O(n²) behavior when calculating depths for all rows
|
|
85
86
|
*/
|
|
86
|
-
const depthCache = new WeakMap<unknown[], Map<string, number
|
|
87
|
+
const depthCache = new WeakMap<unknown[], Map<number, Map<string, number>>>();
|
|
88
|
+
|
|
89
|
+
const logger = createLogger('HierarchicalUtils');
|
|
87
90
|
|
|
88
91
|
/**
|
|
89
92
|
* Gets the depth level of a row in the hierarchy
|
|
@@ -102,13 +105,20 @@ const depthCache = new WeakMap<unknown[], Map<string, number>>();
|
|
|
102
105
|
*/
|
|
103
106
|
export function getRowDepth<TData extends HierarchicalDataRow>(
|
|
104
107
|
row: TData,
|
|
105
|
-
allData: TData[]
|
|
108
|
+
allData: TData[],
|
|
109
|
+
maxDepth: number = 100
|
|
106
110
|
): number {
|
|
107
111
|
// Check cache first
|
|
108
|
-
let
|
|
112
|
+
let cachedDepthsByLimit = depthCache.get(allData);
|
|
113
|
+
if (!cachedDepthsByLimit) {
|
|
114
|
+
cachedDepthsByLimit = new Map();
|
|
115
|
+
depthCache.set(allData, cachedDepthsByLimit);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
let cachedDepths = cachedDepthsByLimit.get(maxDepth);
|
|
109
119
|
if (!cachedDepths) {
|
|
110
120
|
cachedDepths = new Map();
|
|
111
|
-
|
|
121
|
+
cachedDepthsByLimit.set(maxDepth, cachedDepths);
|
|
112
122
|
}
|
|
113
123
|
|
|
114
124
|
// Return cached depth if available
|
|
@@ -118,7 +128,7 @@ export function getRowDepth<TData extends HierarchicalDataRow>(
|
|
|
118
128
|
|
|
119
129
|
// Calculate depth
|
|
120
130
|
let depth = 0;
|
|
121
|
-
|
|
131
|
+
|
|
122
132
|
if (row.isParent) {
|
|
123
133
|
depth = 0;
|
|
124
134
|
} else if (!row.parentId) {
|
|
@@ -131,25 +141,43 @@ export function getRowDepth<TData extends HierarchicalDataRow>(
|
|
|
131
141
|
parentMap.set(item.id, item);
|
|
132
142
|
}
|
|
133
143
|
});
|
|
134
|
-
|
|
144
|
+
|
|
145
|
+
const visited = new Set<string>();
|
|
146
|
+
|
|
135
147
|
// Walk up the parent chain
|
|
136
148
|
let current = row;
|
|
137
|
-
while (current.parentId) {
|
|
149
|
+
while (current.parentId && depth < maxDepth) {
|
|
150
|
+
if (visited.has(current.id)) {
|
|
151
|
+
logger.warn('Circular reference detected while calculating row depth', {
|
|
152
|
+
rowId: row.id,
|
|
153
|
+
currentId: current.id,
|
|
154
|
+
});
|
|
155
|
+
break;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
visited.add(current.id);
|
|
138
159
|
depth++;
|
|
139
160
|
const parent = parentMap.get(current.parentId);
|
|
140
|
-
|
|
161
|
+
|
|
141
162
|
if (!parent || parent.isParent) {
|
|
142
163
|
break;
|
|
143
164
|
}
|
|
144
|
-
|
|
165
|
+
|
|
145
166
|
current = parent;
|
|
146
|
-
|
|
167
|
+
|
|
147
168
|
// Check cache during traversal
|
|
148
169
|
if (cachedDepths.has(current.id)) {
|
|
149
170
|
depth += cachedDepths.get(current.id)!;
|
|
150
171
|
break;
|
|
151
172
|
}
|
|
152
173
|
}
|
|
174
|
+
|
|
175
|
+
if (depth >= maxDepth && current.parentId) {
|
|
176
|
+
logger.warn('Maximum hierarchy depth reached while calculating row depth', {
|
|
177
|
+
rowId: row.id,
|
|
178
|
+
maxDepth,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
153
181
|
}
|
|
154
182
|
|
|
155
183
|
// Cache the result
|
|
@@ -301,13 +301,18 @@ describe('DatePickerWithTimezone Component', () => {
|
|
|
301
301
|
selected: selected,
|
|
302
302
|
onSelect: onSelect,
|
|
303
303
|
initialFocus: true,
|
|
304
|
-
captionLayout: 'dropdown
|
|
305
|
-
|
|
306
|
-
|
|
304
|
+
captionLayout: 'dropdown',
|
|
305
|
+
startMonth: expect.any(Date),
|
|
306
|
+
endMonth: expect.any(Date),
|
|
307
307
|
className: 'p-0'
|
|
308
308
|
}),
|
|
309
309
|
expect.anything()
|
|
310
310
|
);
|
|
311
|
+
|
|
312
|
+
// Verify the date range is correct
|
|
313
|
+
const callArgs = MockedCalendar.mock.calls[0][0];
|
|
314
|
+
expect(callArgs.startMonth).toEqual(new Date(1900, 0));
|
|
315
|
+
expect(callArgs.endMonth).toEqual(new Date(2100, 11));
|
|
311
316
|
});
|
|
312
317
|
});
|
|
313
318
|
});
|
|
@@ -100,16 +100,16 @@ export function DatePickerWithTimezone({
|
|
|
100
100
|
selected={selected}
|
|
101
101
|
onSelect={onSelect}
|
|
102
102
|
initialFocus
|
|
103
|
-
captionLayout="dropdown
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
captionLayout="dropdown"
|
|
104
|
+
startMonth={new Date(1900, 0)}
|
|
105
|
+
endMonth={new Date(2100, 11)}
|
|
106
106
|
className="p-0"
|
|
107
107
|
/>
|
|
108
108
|
</div>
|
|
109
109
|
|
|
110
110
|
<div className="flex items-center justify-between border-t border-border px-3 py-2">
|
|
111
111
|
<div className="flex items-center gap-2 text-sm text-muted-foreground">
|
|
112
|
-
<Clock className="
|
|
112
|
+
<Clock className="size-4" aria-hidden="true" />
|
|
113
113
|
<span>
|
|
114
114
|
Timezone: <span aria-label={`Timezone ${timezoneDisplay}`}>{timezoneDisplay}</span>
|
|
115
115
|
</span>
|
|
@@ -280,7 +280,7 @@ const sizeClasses = {
|
|
|
280
280
|
md: 'max-w-md',
|
|
281
281
|
lg: 'max-w-lg',
|
|
282
282
|
xl: 'max-w-xl',
|
|
283
|
-
full: 'max-w-full
|
|
283
|
+
full: 'max-w-full size-full',
|
|
284
284
|
auto: 'max-w-none w-auto min-w-0'
|
|
285
285
|
};
|
|
286
286
|
|
|
@@ -527,7 +527,7 @@ const DialogContent = React.forwardRef<
|
|
|
527
527
|
{children}
|
|
528
528
|
{showCloseButton && (
|
|
529
529
|
<DialogPrimitive.Close className="absolute right-4 top-4 z-10 rounded-sm opacity-70 ring-offset-background transition-opacity hover:opacity-100 focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:pointer-events-none data-[state=open]:bg-accent data-[state=open]:text-muted-foreground">
|
|
530
|
-
<X className="
|
|
530
|
+
<X className="size-4" />
|
|
531
531
|
<span className="sr-only">Close</span>
|
|
532
532
|
</DialogPrimitive.Close>
|
|
533
533
|
)}
|
|
@@ -296,7 +296,7 @@ export function EventSelector({
|
|
|
296
296
|
return (
|
|
297
297
|
<div className={className}>
|
|
298
298
|
<Alert variant="destructive">
|
|
299
|
-
<Lock className="
|
|
299
|
+
<Lock className="size-4" />
|
|
300
300
|
<AlertDescription className="flex items-center justify-between">
|
|
301
301
|
<span>{error.message}</span>
|
|
302
302
|
{showRetryButton && (
|
|
@@ -306,7 +306,7 @@ export function EventSelector({
|
|
|
306
306
|
onClick={handleRetry}
|
|
307
307
|
className="ml-2"
|
|
308
308
|
>
|
|
309
|
-
<RefreshCw className="
|
|
309
|
+
<RefreshCw className="size-3 mr-1" />
|
|
310
310
|
Retry
|
|
311
311
|
</Button>
|
|
312
312
|
)}
|
|
@@ -322,7 +322,7 @@ export function EventSelector({
|
|
|
322
322
|
return (
|
|
323
323
|
<div className={className}>
|
|
324
324
|
<Alert variant="inline">
|
|
325
|
-
<AlertCircle className="
|
|
325
|
+
<AlertCircle className="size-4 text-acc-700" />
|
|
326
326
|
<AlertDescription className="flex items-center justify-between">
|
|
327
327
|
<span>No events available.</span>
|
|
328
328
|
{showRetryButton && (
|
|
@@ -332,7 +332,7 @@ export function EventSelector({
|
|
|
332
332
|
onClick={handleRetry}
|
|
333
333
|
className="ml-2"
|
|
334
334
|
>
|
|
335
|
-
<RefreshCw className="
|
|
335
|
+
<RefreshCw className="size-3 mr-1" />
|
|
336
336
|
Refresh
|
|
337
337
|
</Button>
|
|
338
338
|
)}
|
|
@@ -355,7 +355,7 @@ export function EventSelector({
|
|
|
355
355
|
<SelectValue placeholder={placeholder}>
|
|
356
356
|
{selectedEvent && (
|
|
357
357
|
<div className="flex items-center gap-2">
|
|
358
|
-
<Calendar className="
|
|
358
|
+
<Calendar className="size-4 flex-shrink-0" />
|
|
359
359
|
<span className="truncate">{selectedEvent.event_name}</span>
|
|
360
360
|
{selectedEvent.event_date && (
|
|
361
361
|
<span className="text-xs text-muted-foreground flex-shrink-0">
|
|
@@ -380,7 +380,7 @@ export function EventSelector({
|
|
|
380
380
|
>
|
|
381
381
|
<div className="flex items-center gap-2 w-full">
|
|
382
382
|
{showNextEventIndicator && isNext && (
|
|
383
|
-
<Star className="
|
|
383
|
+
<Star className="size-3 text-acc-500" />
|
|
384
384
|
)}
|
|
385
385
|
<div className="flex-1">
|
|
386
386
|
<div className="flex items-center gap-2">
|
|
@@ -395,7 +395,7 @@ export function EventSelector({
|
|
|
395
395
|
</div>
|
|
396
396
|
{showEventDetails && event.event_date && (
|
|
397
397
|
<div className="flex items-center gap-1 text-xs text-muted-foreground">
|
|
398
|
-
<Calendar className="
|
|
398
|
+
<Calendar className="size-3" />
|
|
399
399
|
<span>{formatEventDate(event.event_date)}</span>
|
|
400
400
|
{showNextEventIndicator && isNext && (
|
|
401
401
|
<span className="text-acc-600 font-medium">
|