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