@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
|
@@ -35,6 +35,15 @@ var OrganisationContextRequiredError = class extends RBACError {
|
|
|
35
35
|
this.name = "OrganisationContextRequiredError";
|
|
36
36
|
}
|
|
37
37
|
};
|
|
38
|
+
var EventContextRequiredError = class extends RBACError {
|
|
39
|
+
constructor() {
|
|
40
|
+
super(
|
|
41
|
+
"Event context is required for this operation",
|
|
42
|
+
"EVENT_CONTEXT_REQUIRED"
|
|
43
|
+
);
|
|
44
|
+
this.name = "EventContextRequiredError";
|
|
45
|
+
}
|
|
46
|
+
};
|
|
38
47
|
var RBACNotInitializedError = class extends RBACError {
|
|
39
48
|
constructor() {
|
|
40
49
|
super(
|
|
@@ -428,19 +437,32 @@ var RBACCacheInvalidationManager = class {
|
|
|
428
437
|
log.warn("Failed to log cache invalidation audit event:", error);
|
|
429
438
|
});
|
|
430
439
|
}
|
|
440
|
+
/**
|
|
441
|
+
* Cleanup subscriptions only (not all callbacks)
|
|
442
|
+
* Used internally to cleanup before setting up new subscriptions
|
|
443
|
+
*/
|
|
444
|
+
cleanupSubscriptions() {
|
|
445
|
+
this.channels.forEach((channel) => {
|
|
446
|
+
try {
|
|
447
|
+
if (channel && typeof channel.unsubscribe === "function") {
|
|
448
|
+
channel.unsubscribe();
|
|
449
|
+
}
|
|
450
|
+
} catch (error) {
|
|
451
|
+
log.warn("Failed to unsubscribe from channel:", error);
|
|
452
|
+
}
|
|
453
|
+
});
|
|
454
|
+
this.channels = [];
|
|
455
|
+
}
|
|
431
456
|
/**
|
|
432
457
|
* Setup realtime subscriptions for automatic cache invalidation
|
|
433
|
-
*
|
|
458
|
+
* Always cleans up existing subscriptions before setting up new ones to prevent duplicates
|
|
434
459
|
*/
|
|
435
460
|
setupRealtimeSubscriptions() {
|
|
461
|
+
this.cleanupSubscriptions();
|
|
436
462
|
if (!this.supabase.channel || typeof this.supabase.channel !== "function") {
|
|
437
463
|
log.debug("Realtime not available, skipping subscriptions");
|
|
438
464
|
return;
|
|
439
465
|
}
|
|
440
|
-
if (this.channels.length > 0) {
|
|
441
|
-
log.debug("Realtime subscriptions already set up, skipping duplicate setup");
|
|
442
|
-
return;
|
|
443
|
-
}
|
|
444
466
|
const orgRolesChannel = this.supabase.channel("rbac_organisation_roles_changes").on("postgres_changes", {
|
|
445
467
|
event: "*",
|
|
446
468
|
schema: "public",
|
|
@@ -672,8 +694,226 @@ function mapErrorCategoryToSecurityEventType(category) {
|
|
|
672
694
|
}
|
|
673
695
|
}
|
|
674
696
|
|
|
697
|
+
// src/rbac/utils/eventContext.ts
|
|
698
|
+
var orgDerivationCache = /* @__PURE__ */ new Map();
|
|
699
|
+
var MAX_CACHE_SIZE = 100;
|
|
700
|
+
async function getOrganisationFromEvent(supabase, eventId) {
|
|
701
|
+
if (orgDerivationCache.has(eventId)) {
|
|
702
|
+
return orgDerivationCache.get(eventId) ?? null;
|
|
703
|
+
}
|
|
704
|
+
const { data, error } = await supabase.from("event").select("organisation_id").eq("event_id", eventId).single();
|
|
705
|
+
let organisationId = null;
|
|
706
|
+
if (error || !data) {
|
|
707
|
+
organisationId = null;
|
|
708
|
+
} else {
|
|
709
|
+
organisationId = data.organisation_id;
|
|
710
|
+
}
|
|
711
|
+
if (orgDerivationCache.size >= MAX_CACHE_SIZE) {
|
|
712
|
+
const firstKey = orgDerivationCache.keys().next().value;
|
|
713
|
+
if (firstKey) {
|
|
714
|
+
orgDerivationCache.delete(firstKey);
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
orgDerivationCache.set(eventId, organisationId);
|
|
718
|
+
return organisationId;
|
|
719
|
+
}
|
|
720
|
+
|
|
721
|
+
// src/rbac/utils/contextValidator.ts
|
|
722
|
+
var log2 = createLogger("ContextValidator");
|
|
723
|
+
function allowsOptionalContexts(appName) {
|
|
724
|
+
return appName === "PORTAL" || appName === "ADMIN";
|
|
725
|
+
}
|
|
726
|
+
var ContextValidator = class {
|
|
727
|
+
/**
|
|
728
|
+
* Validate scope against app requirements
|
|
729
|
+
*
|
|
730
|
+
* @param scope - Current scope
|
|
731
|
+
* @param appConfig - App configuration (requires_event flag)
|
|
732
|
+
* @param appName - App name (for PORTAL/ADMIN special case)
|
|
733
|
+
* @returns Validation result with resolved scope
|
|
734
|
+
*/
|
|
735
|
+
static async validateScope(scope, appConfig, appName) {
|
|
736
|
+
if (allowsOptionalContexts(appName)) {
|
|
737
|
+
return {
|
|
738
|
+
isValid: true,
|
|
739
|
+
resolvedScope: {
|
|
740
|
+
organisationId: scope.organisationId,
|
|
741
|
+
eventId: scope.eventId,
|
|
742
|
+
appId: scope.appId
|
|
743
|
+
},
|
|
744
|
+
error: null
|
|
745
|
+
};
|
|
746
|
+
}
|
|
747
|
+
if (!appConfig) {
|
|
748
|
+
if (!scope.organisationId) {
|
|
749
|
+
return {
|
|
750
|
+
isValid: false,
|
|
751
|
+
resolvedScope: null,
|
|
752
|
+
error: new OrganisationContextRequiredError()
|
|
753
|
+
};
|
|
754
|
+
}
|
|
755
|
+
return {
|
|
756
|
+
isValid: true,
|
|
757
|
+
resolvedScope: scope,
|
|
758
|
+
error: null
|
|
759
|
+
};
|
|
760
|
+
}
|
|
761
|
+
if (appConfig.requires_event) {
|
|
762
|
+
if (!scope.eventId) {
|
|
763
|
+
return {
|
|
764
|
+
isValid: false,
|
|
765
|
+
resolvedScope: null,
|
|
766
|
+
error: new EventContextRequiredError()
|
|
767
|
+
};
|
|
768
|
+
}
|
|
769
|
+
return {
|
|
770
|
+
isValid: true,
|
|
771
|
+
resolvedScope: scope,
|
|
772
|
+
error: null
|
|
773
|
+
};
|
|
774
|
+
}
|
|
775
|
+
if (!scope.organisationId) {
|
|
776
|
+
return {
|
|
777
|
+
isValid: false,
|
|
778
|
+
resolvedScope: null,
|
|
779
|
+
error: new OrganisationContextRequiredError()
|
|
780
|
+
};
|
|
781
|
+
}
|
|
782
|
+
return {
|
|
783
|
+
isValid: true,
|
|
784
|
+
resolvedScope: scope,
|
|
785
|
+
error: null
|
|
786
|
+
};
|
|
787
|
+
}
|
|
788
|
+
/**
|
|
789
|
+
* Resolve required context and derive missing values
|
|
790
|
+
*
|
|
791
|
+
* @param scope - Current scope
|
|
792
|
+
* @param appConfig - App configuration
|
|
793
|
+
* @param appName - App name (for PORTAL/ADMIN special case)
|
|
794
|
+
* @param supabase - Supabase client (for deriving org from event)
|
|
795
|
+
* @returns Resolved scope with all required context
|
|
796
|
+
*/
|
|
797
|
+
static async resolveRequiredContext(scope, appConfig, appName, supabase) {
|
|
798
|
+
if (allowsOptionalContexts(appName)) {
|
|
799
|
+
return {
|
|
800
|
+
isValid: true,
|
|
801
|
+
resolvedScope: {
|
|
802
|
+
organisationId: scope.organisationId,
|
|
803
|
+
eventId: scope.eventId,
|
|
804
|
+
appId: scope.appId
|
|
805
|
+
},
|
|
806
|
+
error: null
|
|
807
|
+
};
|
|
808
|
+
}
|
|
809
|
+
if (!appConfig) {
|
|
810
|
+
if (!scope.organisationId) {
|
|
811
|
+
return {
|
|
812
|
+
isValid: false,
|
|
813
|
+
resolvedScope: null,
|
|
814
|
+
error: new OrganisationContextRequiredError()
|
|
815
|
+
};
|
|
816
|
+
}
|
|
817
|
+
return {
|
|
818
|
+
isValid: true,
|
|
819
|
+
resolvedScope: scope,
|
|
820
|
+
error: null
|
|
821
|
+
};
|
|
822
|
+
}
|
|
823
|
+
if (appConfig.requires_event) {
|
|
824
|
+
if (!scope.eventId) {
|
|
825
|
+
return {
|
|
826
|
+
isValid: false,
|
|
827
|
+
resolvedScope: null,
|
|
828
|
+
error: new EventContextRequiredError()
|
|
829
|
+
};
|
|
830
|
+
}
|
|
831
|
+
let organisationId = scope.organisationId;
|
|
832
|
+
if (!organisationId && supabase && scope.eventId) {
|
|
833
|
+
try {
|
|
834
|
+
const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
|
|
835
|
+
organisationId = derivedOrgId || void 0;
|
|
836
|
+
if (!organisationId) {
|
|
837
|
+
return {
|
|
838
|
+
isValid: false,
|
|
839
|
+
resolvedScope: null,
|
|
840
|
+
error: new Error("Could not resolve organisation from event context")
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
} catch (error) {
|
|
844
|
+
log2.error("Failed to derive org from event:", error);
|
|
845
|
+
return {
|
|
846
|
+
isValid: false,
|
|
847
|
+
resolvedScope: null,
|
|
848
|
+
error: error instanceof Error ? error : new Error("Failed to derive organisation from event")
|
|
849
|
+
};
|
|
850
|
+
}
|
|
851
|
+
} else if (!organisationId) {
|
|
852
|
+
return {
|
|
853
|
+
isValid: false,
|
|
854
|
+
resolvedScope: null,
|
|
855
|
+
error: new Error("Event context requires organisationId but it could not be derived (supabase client not available)")
|
|
856
|
+
};
|
|
857
|
+
}
|
|
858
|
+
return {
|
|
859
|
+
isValid: true,
|
|
860
|
+
resolvedScope: {
|
|
861
|
+
organisationId,
|
|
862
|
+
eventId: scope.eventId,
|
|
863
|
+
appId: scope.appId
|
|
864
|
+
},
|
|
865
|
+
error: null
|
|
866
|
+
};
|
|
867
|
+
}
|
|
868
|
+
if (!scope.organisationId) {
|
|
869
|
+
return {
|
|
870
|
+
isValid: false,
|
|
871
|
+
resolvedScope: null,
|
|
872
|
+
error: new OrganisationContextRequiredError()
|
|
873
|
+
};
|
|
874
|
+
}
|
|
875
|
+
return {
|
|
876
|
+
isValid: true,
|
|
877
|
+
resolvedScope: scope,
|
|
878
|
+
error: null
|
|
879
|
+
};
|
|
880
|
+
}
|
|
881
|
+
/**
|
|
882
|
+
* Derive organisation ID from event ID
|
|
883
|
+
*
|
|
884
|
+
* @param supabase - Supabase client
|
|
885
|
+
* @param eventId - Event ID
|
|
886
|
+
* @returns Organisation ID or null
|
|
887
|
+
*/
|
|
888
|
+
static async deriveOrgFromEvent(supabase, eventId) {
|
|
889
|
+
return getOrganisationFromEvent(supabase, eventId);
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Check if context is ready for permission checks
|
|
893
|
+
*
|
|
894
|
+
* @param scope - Current scope
|
|
895
|
+
* @param appConfig - App configuration
|
|
896
|
+
* @param appName - App name
|
|
897
|
+
* @param hasSelectedEvent - Whether event is selected
|
|
898
|
+
* @param hasSelectedOrganisation - Whether organisation is selected
|
|
899
|
+
* @returns True if context is ready
|
|
900
|
+
*/
|
|
901
|
+
static isContextReady(scope, appConfig, appName, hasSelectedEvent, hasSelectedOrganisation) {
|
|
902
|
+
if (allowsOptionalContexts(appName)) {
|
|
903
|
+
return true;
|
|
904
|
+
}
|
|
905
|
+
if (!appConfig) {
|
|
906
|
+
return !!hasSelectedOrganisation || !!scope.organisationId;
|
|
907
|
+
}
|
|
908
|
+
if (appConfig.requires_event) {
|
|
909
|
+
return !!hasSelectedEvent || !!scope.eventId;
|
|
910
|
+
}
|
|
911
|
+
return !!hasSelectedOrganisation || !!scope.organisationId;
|
|
912
|
+
}
|
|
913
|
+
};
|
|
914
|
+
|
|
675
915
|
// src/rbac/security.ts
|
|
676
|
-
var
|
|
916
|
+
var log3 = createLogger("RBACSecurity");
|
|
677
917
|
var RBACSecurityValidator = class {
|
|
678
918
|
/**
|
|
679
919
|
* Validate permission string format
|
|
@@ -782,19 +1022,13 @@ var RBACSecurityValidator = class {
|
|
|
782
1022
|
/**
|
|
783
1023
|
* Validate context requirements for security
|
|
784
1024
|
* @param scope - Scope object
|
|
785
|
-
* @param
|
|
1025
|
+
* @param appConfig - App configuration
|
|
1026
|
+
* @param appName - App name (for PORTAL special case)
|
|
786
1027
|
* @returns True if context is valid, false otherwise
|
|
787
1028
|
*/
|
|
788
|
-
static validateContextRequirements(scope,
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
}
|
|
792
|
-
if (appId && scope.appId === appId) {
|
|
793
|
-
if (!scope.eventId) {
|
|
794
|
-
return false;
|
|
795
|
-
}
|
|
796
|
-
}
|
|
797
|
-
return true;
|
|
1029
|
+
static async validateContextRequirements(scope, appConfig, appName) {
|
|
1030
|
+
const validation = await ContextValidator.validateScope(scope, appConfig || null, appName);
|
|
1031
|
+
return validation.isValid;
|
|
798
1032
|
}
|
|
799
1033
|
// Only warn once per 5 seconds per user
|
|
800
1034
|
static logSecurityEvent(event) {
|
|
@@ -813,7 +1047,7 @@ var RBACSecurityValidator = class {
|
|
|
813
1047
|
this.rateLimitWarningCount.set(event.userId, userWarning);
|
|
814
1048
|
return;
|
|
815
1049
|
} else {
|
|
816
|
-
|
|
1050
|
+
log3.warn("Security event (throttled):", {
|
|
817
1051
|
...securityEvent,
|
|
818
1052
|
details: {
|
|
819
1053
|
...securityEvent.details,
|
|
@@ -826,11 +1060,11 @@ var RBACSecurityValidator = class {
|
|
|
826
1060
|
}
|
|
827
1061
|
} else {
|
|
828
1062
|
this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });
|
|
829
|
-
|
|
1063
|
+
log3.warn("Security event:", securityEvent);
|
|
830
1064
|
return;
|
|
831
1065
|
}
|
|
832
1066
|
}
|
|
833
|
-
|
|
1067
|
+
log3.warn("Security event:", securityEvent);
|
|
834
1068
|
}
|
|
835
1069
|
/**
|
|
836
1070
|
* Get severity level for security event
|
|
@@ -902,10 +1136,18 @@ var RBACSecurityMiddleware = class {
|
|
|
902
1136
|
if (!RBACSecurityValidator.validateUserId(context.userId)) {
|
|
903
1137
|
errors.push("Invalid user ID format");
|
|
904
1138
|
}
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
1139
|
+
const isPagePermission = input.permission?.includes(":page.") || !!input.pageId;
|
|
1140
|
+
const requiresOrgId = !isPagePermission;
|
|
1141
|
+
if (requiresOrgId) {
|
|
1142
|
+
if (!context.organisationId) {
|
|
1143
|
+
errors.push("Organisation ID is required for resource-level permissions");
|
|
1144
|
+
} else if (!RBACSecurityValidator.validateUUID(context.organisationId)) {
|
|
1145
|
+
errors.push("Invalid organisation ID format");
|
|
1146
|
+
}
|
|
1147
|
+
} else {
|
|
1148
|
+
if (context.organisationId && !RBACSecurityValidator.validateUUID(context.organisationId)) {
|
|
1149
|
+
errors.push("Invalid organisation ID format");
|
|
1150
|
+
}
|
|
909
1151
|
}
|
|
910
1152
|
if (input.permission && !RBACSecurityValidator.validatePermission(input.permission)) {
|
|
911
1153
|
errors.push("Invalid permission format");
|
|
@@ -1252,7 +1494,8 @@ var RBACEngine = class {
|
|
|
1252
1494
|
return "super";
|
|
1253
1495
|
}
|
|
1254
1496
|
if (scope.organisationId) {
|
|
1255
|
-
const { data:
|
|
1497
|
+
const { data: orgRoles } = await this.supabase.from("rbac_organisation_roles").select("role").eq("user_id", userId).eq("organisation_id", scope.organisationId).eq("status", "active").is("revoked_at", null).lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).limit(1);
|
|
1498
|
+
const orgRole = orgRoles?.[0];
|
|
1256
1499
|
if (orgRole?.role === "org_admin") {
|
|
1257
1500
|
rbacCache.set(cacheKey, "admin", 6e4);
|
|
1258
1501
|
return "admin";
|
|
@@ -1598,6 +1841,7 @@ function generateDeduplicationKey(input) {
|
|
|
1598
1841
|
return RBACCache.generatePermissionKey({
|
|
1599
1842
|
userId: input.userId,
|
|
1600
1843
|
organisationId: input.scope.organisationId,
|
|
1844
|
+
// Can be undefined for page-level permissions
|
|
1601
1845
|
eventId: input.scope.eventId,
|
|
1602
1846
|
appId: input.scope.appId,
|
|
1603
1847
|
permission: input.permission,
|
|
@@ -1624,7 +1868,7 @@ function getInFlightRequestCount() {
|
|
|
1624
1868
|
}
|
|
1625
1869
|
|
|
1626
1870
|
// src/rbac/api.ts
|
|
1627
|
-
var
|
|
1871
|
+
var log4 = createLogger("RBACAPI");
|
|
1628
1872
|
var globalEngine = null;
|
|
1629
1873
|
function setupRBAC(supabase, config) {
|
|
1630
1874
|
const logger = getRBACLogger();
|
|
@@ -1662,37 +1906,116 @@ function getEngine() {
|
|
|
1662
1906
|
}
|
|
1663
1907
|
return globalEngine;
|
|
1664
1908
|
}
|
|
1665
|
-
async function getAccessLevel(input) {
|
|
1909
|
+
async function getAccessLevel(input, appConfig, appName) {
|
|
1666
1910
|
const engine = getEngine();
|
|
1667
|
-
|
|
1911
|
+
const isSuperAdminUser = await engine["checkSuperAdmin"](input.userId);
|
|
1912
|
+
if (isSuperAdminUser) {
|
|
1913
|
+
return "super";
|
|
1914
|
+
}
|
|
1915
|
+
let resolvedAppConfig = appConfig ?? null;
|
|
1916
|
+
let resolvedAppName = appName;
|
|
1917
|
+
if (!resolvedAppConfig && input.scope.appId) {
|
|
1918
|
+
resolvedAppConfig = await getAppConfig(input.scope.appId);
|
|
1919
|
+
}
|
|
1920
|
+
const validation = await ContextValidator.resolveRequiredContext(
|
|
1921
|
+
input.scope,
|
|
1922
|
+
resolvedAppConfig,
|
|
1923
|
+
resolvedAppName,
|
|
1924
|
+
engine["supabase"]
|
|
1925
|
+
);
|
|
1926
|
+
if (!validation.isValid || !validation.resolvedScope) {
|
|
1927
|
+
throw validation.error || new OrganisationContextRequiredError();
|
|
1928
|
+
}
|
|
1929
|
+
return engine.getAccessLevel({
|
|
1930
|
+
...input,
|
|
1931
|
+
scope: validation.resolvedScope
|
|
1932
|
+
});
|
|
1668
1933
|
}
|
|
1669
|
-
async function getPermissionMap(input) {
|
|
1934
|
+
async function getPermissionMap(input, appConfig, appName) {
|
|
1670
1935
|
const engine = getEngine();
|
|
1671
|
-
|
|
1936
|
+
let resolvedAppConfig = appConfig ?? null;
|
|
1937
|
+
let resolvedAppName = appName;
|
|
1938
|
+
if (!resolvedAppConfig && input.scope.appId) {
|
|
1939
|
+
resolvedAppConfig = await getAppConfig(input.scope.appId);
|
|
1940
|
+
}
|
|
1941
|
+
const validation = await ContextValidator.resolveRequiredContext(
|
|
1942
|
+
input.scope,
|
|
1943
|
+
resolvedAppConfig,
|
|
1944
|
+
resolvedAppName,
|
|
1945
|
+
engine["supabase"]
|
|
1946
|
+
);
|
|
1947
|
+
if (!validation.isValid || !validation.resolvedScope) {
|
|
1948
|
+
throw validation.error || new OrganisationContextRequiredError();
|
|
1949
|
+
}
|
|
1950
|
+
return engine.getPermissionMap({
|
|
1951
|
+
...input,
|
|
1952
|
+
scope: validation.resolvedScope
|
|
1953
|
+
});
|
|
1672
1954
|
}
|
|
1673
1955
|
async function resolveAppContext(input) {
|
|
1674
1956
|
const engine = getEngine();
|
|
1675
1957
|
return engine.resolveAppContext(input);
|
|
1676
1958
|
}
|
|
1677
|
-
async function getRoleContext(input) {
|
|
1959
|
+
async function getRoleContext(input, appConfig, appName) {
|
|
1678
1960
|
const engine = getEngine();
|
|
1679
|
-
|
|
1961
|
+
let resolvedAppConfig = appConfig ?? null;
|
|
1962
|
+
let resolvedAppName = appName;
|
|
1963
|
+
if (!resolvedAppConfig && input.scope.appId) {
|
|
1964
|
+
resolvedAppConfig = await getAppConfig(input.scope.appId);
|
|
1965
|
+
}
|
|
1966
|
+
const validation = await ContextValidator.resolveRequiredContext(
|
|
1967
|
+
input.scope,
|
|
1968
|
+
resolvedAppConfig,
|
|
1969
|
+
resolvedAppName,
|
|
1970
|
+
engine["supabase"]
|
|
1971
|
+
);
|
|
1972
|
+
if (!validation.isValid || !validation.resolvedScope) {
|
|
1973
|
+
throw validation.error || new OrganisationContextRequiredError();
|
|
1974
|
+
}
|
|
1975
|
+
return engine.getRoleContext({
|
|
1976
|
+
...input,
|
|
1977
|
+
scope: validation.resolvedScope
|
|
1978
|
+
});
|
|
1680
1979
|
}
|
|
1681
|
-
async function isPermitted(input) {
|
|
1980
|
+
async function isPermitted(input, appConfig, appName) {
|
|
1682
1981
|
const engine = getEngine();
|
|
1683
|
-
|
|
1684
|
-
|
|
1982
|
+
let resolvedAppConfig = appConfig ?? null;
|
|
1983
|
+
let resolvedAppName = appName;
|
|
1984
|
+
if (!resolvedAppConfig && input.scope.appId) {
|
|
1985
|
+
resolvedAppConfig = await getAppConfig(input.scope.appId);
|
|
1685
1986
|
}
|
|
1987
|
+
if (!resolvedAppName && input.scope.appId) {
|
|
1988
|
+
try {
|
|
1989
|
+
const { data } = await engine["supabase"].from("rbac_apps").select("name").eq("id", input.scope.appId).eq("is_active", true).single();
|
|
1990
|
+
if (data) {
|
|
1991
|
+
resolvedAppName = data.name;
|
|
1992
|
+
}
|
|
1993
|
+
} catch (err) {
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
const validation = await ContextValidator.resolveRequiredContext(
|
|
1997
|
+
input.scope,
|
|
1998
|
+
resolvedAppConfig,
|
|
1999
|
+
resolvedAppName,
|
|
2000
|
+
engine["supabase"]
|
|
2001
|
+
);
|
|
2002
|
+
if (!validation.isValid || !validation.resolvedScope) {
|
|
2003
|
+
throw validation.error || new OrganisationContextRequiredError();
|
|
2004
|
+
}
|
|
2005
|
+
const validatedScope = validation.resolvedScope;
|
|
1686
2006
|
const securityContext = {
|
|
1687
2007
|
userId: input.userId,
|
|
1688
|
-
organisationId:
|
|
1689
|
-
// Required - no fallback
|
|
2008
|
+
organisationId: validatedScope.organisationId || null,
|
|
1690
2009
|
timestamp: /* @__PURE__ */ new Date()
|
|
1691
2010
|
// Optional fields can be omitted
|
|
1692
2011
|
};
|
|
1693
|
-
|
|
2012
|
+
const validatedInput = {
|
|
2013
|
+
...input,
|
|
2014
|
+
scope: validatedScope
|
|
2015
|
+
};
|
|
2016
|
+
return engine.isPermitted(validatedInput, securityContext);
|
|
1694
2017
|
}
|
|
1695
|
-
async function isPermittedCached(input) {
|
|
2018
|
+
async function isPermittedCached(input, appConfig, appName) {
|
|
1696
2019
|
const { userId, scope, permission, pageId } = input;
|
|
1697
2020
|
const cacheKey = RBACCache.generatePermissionKey({
|
|
1698
2021
|
userId,
|
|
@@ -1707,7 +2030,7 @@ async function isPermittedCached(input) {
|
|
|
1707
2030
|
return cached;
|
|
1708
2031
|
}
|
|
1709
2032
|
return getOrCreateRequest(input, async (checkInput) => {
|
|
1710
|
-
const result = await isPermitted(checkInput);
|
|
2033
|
+
const result = await isPermitted(checkInput, appConfig, appName);
|
|
1711
2034
|
const isPageLevelCheck = !!pageId || permission.includes("page.");
|
|
1712
2035
|
rbacCache.set(cacheKey, result, void 0, isPageLevelCheck);
|
|
1713
2036
|
return result;
|
|
@@ -1747,18 +2070,48 @@ async function isSuperAdmin(userId) {
|
|
|
1747
2070
|
return engine["checkSuperAdmin"](userId);
|
|
1748
2071
|
}
|
|
1749
2072
|
async function getAppConfig(appId) {
|
|
1750
|
-
|
|
1751
|
-
|
|
2073
|
+
try {
|
|
2074
|
+
const engine = getEngine();
|
|
2075
|
+
return getAppConfigWithClient(engine["supabase"], appId);
|
|
2076
|
+
} catch (err) {
|
|
2077
|
+
if (err instanceof RBACNotInitializedError) {
|
|
2078
|
+
return null;
|
|
2079
|
+
}
|
|
2080
|
+
throw err;
|
|
2081
|
+
}
|
|
1752
2082
|
}
|
|
1753
2083
|
async function getAppConfigWithClient(client, appId) {
|
|
2084
|
+
if (!client) {
|
|
2085
|
+
return null;
|
|
2086
|
+
}
|
|
2087
|
+
const cacheKey = `app_config:${appId}`;
|
|
2088
|
+
const cached = rbacCache.get(cacheKey, true);
|
|
2089
|
+
if (cached !== null) {
|
|
2090
|
+
return cached;
|
|
2091
|
+
}
|
|
2092
|
+
try {
|
|
2093
|
+
const { data, error } = await client.from("rbac_apps").select("requires_event, name").eq("id", appId).eq("is_active", true).single();
|
|
2094
|
+
if (error || !data) {
|
|
2095
|
+
return null;
|
|
2096
|
+
}
|
|
2097
|
+
const appConfig = { requires_event: data.requires_event ?? false };
|
|
2098
|
+
rbacCache.set(cacheKey, appConfig, 5 * 60 * 1e3, true);
|
|
2099
|
+
return appConfig;
|
|
2100
|
+
} catch (err) {
|
|
2101
|
+
log4.error("Error fetching app config:", err);
|
|
2102
|
+
return null;
|
|
2103
|
+
}
|
|
2104
|
+
}
|
|
2105
|
+
async function getAppConfigByName(appName) {
|
|
2106
|
+
const engine = getEngine();
|
|
1754
2107
|
try {
|
|
1755
|
-
const { data, error } = await
|
|
2108
|
+
const { data, error } = await engine["supabase"].from("rbac_apps").select("requires_event, name").eq("name", appName).eq("is_active", true).single();
|
|
1756
2109
|
if (error || !data) {
|
|
1757
2110
|
return null;
|
|
1758
2111
|
}
|
|
1759
|
-
return { requires_event: data.requires_event };
|
|
2112
|
+
return { requires_event: data.requires_event ?? false };
|
|
1760
2113
|
} catch (err) {
|
|
1761
|
-
|
|
2114
|
+
log4.error("Error fetching app config by name:", err);
|
|
1762
2115
|
return null;
|
|
1763
2116
|
}
|
|
1764
2117
|
}
|
|
@@ -1807,6 +2160,7 @@ export {
|
|
|
1807
2160
|
RBACCache,
|
|
1808
2161
|
rbacCache,
|
|
1809
2162
|
CACHE_PATTERNS,
|
|
2163
|
+
ContextValidator,
|
|
1810
2164
|
createRBACConfig,
|
|
1811
2165
|
getRBACConfig,
|
|
1812
2166
|
getRBACLogger,
|
|
@@ -1837,6 +2191,7 @@ export {
|
|
|
1837
2191
|
isSuperAdmin,
|
|
1838
2192
|
getAppConfig,
|
|
1839
2193
|
getAppConfigWithClient,
|
|
2194
|
+
getAppConfigByName,
|
|
1840
2195
|
isOrganisationAdmin,
|
|
1841
2196
|
isEventAdmin,
|
|
1842
2197
|
invalidateUserCache,
|
|
@@ -1845,4 +2200,4 @@ export {
|
|
|
1845
2200
|
invalidateAppCache,
|
|
1846
2201
|
clearCache
|
|
1847
2202
|
};
|
|
1848
|
-
//# sourceMappingURL=chunk-
|
|
2203
|
+
//# sourceMappingURL=chunk-RUYZKXOD.js.map
|