@jmruthers/pace-core 0.5.183 → 0.5.185
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +38 -0
- package/README.md +60 -1
- package/core-usage-manifest.json +312 -0
- package/dist/{DataTable-QAB34V6K.js → DataTable-IX2NBUTP.js} +6 -6
- package/dist/{DataTable-Bz8ffqyA.d.ts → DataTable-Z9NLVJh0.d.ts} +1 -1
- package/dist/{index-Bl--n7-T.d.ts → PublicPageProvider-BABf6JCh.d.ts} +21 -10
- package/dist/{UnifiedAuthProvider-7F6T4B6K.js → UnifiedAuthProvider-A4BCQRJY.js} +4 -2
- package/dist/{UnifiedAuthProvider-F86d7dSi.d.ts → UnifiedAuthProvider-BG0AL5eE.d.ts} +2 -1
- package/dist/{api-ROMBCNKU.js → api-BMFCXVQX.js} +2 -2
- package/dist/{chunk-RA3JUFMW.js → chunk-445GEP27.js} +154 -4
- package/dist/{chunk-RA3JUFMW.js.map → chunk-445GEP27.js.map} +1 -1
- package/dist/{chunk-CSOFYHAG.js → chunk-AISXLWGZ.js} +374 -60
- package/dist/chunk-AISXLWGZ.js.map +1 -0
- package/dist/{chunk-FUEYYMX5.js → chunk-FXFJRTKI.js} +24 -3
- package/dist/chunk-FXFJRTKI.js.map +1 -0
- package/dist/{chunk-QETLRQI6.js → chunk-HC67NW5K.js} +380 -360
- package/dist/chunk-HC67NW5K.js.map +1 -0
- package/dist/chunk-HESYZWZW.js +388 -0
- package/dist/chunk-HESYZWZW.js.map +1 -0
- package/dist/{chunk-QUVSNGIP.js → chunk-HGPQUCBC.js} +34 -9
- package/dist/{chunk-QUVSNGIP.js.map → chunk-HGPQUCBC.js.map} +1 -1
- package/dist/{chunk-UHNYIBXL.js → chunk-IXSNYUCT.js} +1 -1
- package/dist/chunk-IXSNYUCT.js.map +1 -0
- package/dist/{chunk-MI7HBHN3.js → chunk-MX3EIJGQ.js} +4 -3
- package/dist/{chunk-MI7HBHN3.js.map → chunk-MX3EIJGQ.js.map} +1 -1
- package/dist/{chunk-PWAHJW4G.js → chunk-OKI34GZD.js} +86 -33
- package/dist/chunk-OKI34GZD.js.map +1 -0
- package/dist/{chunk-W22JP75J.js → chunk-STTZQK2I.js} +3 -3
- package/dist/chunk-THRPYOFK.js +215 -0
- package/dist/chunk-THRPYOFK.js.map +1 -0
- package/dist/{chunk-M7W4CP3M.js → chunk-U6WNSFX5.js} +2 -1
- package/dist/chunk-U6WNSFX5.js.map +1 -0
- package/dist/{chunk-QCDXODCA.js → chunk-XAUHJD3L.js} +2 -2
- package/dist/components.d.ts +182 -6
- package/dist/components.js +157 -11
- package/dist/components.js.map +1 -1
- package/dist/eslint-rules/pace-core-compliance.cjs +406 -0
- package/dist/{file-reference-D06mEEWW.d.ts → file-reference-BjR39ktt.d.ts} +7 -1
- package/dist/hooks.d.ts +7 -14
- package/dist/hooks.js +10 -22
- package/dist/hooks.js.map +1 -1
- package/dist/index.d.ts +11 -11
- package/dist/index.js +79 -16
- package/dist/index.js.map +1 -1
- package/dist/providers.d.ts +1 -1
- package/dist/providers.js +3 -1
- package/dist/rbac/index.d.ts +205 -14
- package/dist/rbac/index.js +28 -6
- package/dist/timezone-_pgH8qrY.d.ts +530 -0
- package/dist/{types-_x1f4QBF.d.ts → types-DUyCRSTj.d.ts} +1 -1
- package/dist/types.d.ts +1 -1
- package/dist/types.js +1 -1
- package/dist/{usePublicRouteParams-JJczomYq.d.ts → usePublicRouteParams-CvnC3d-e.d.ts} +113 -2
- package/dist/utils.d.ts +109 -151
- package/dist/utils.js +128 -138
- package/dist/utils.js.map +1 -1
- package/docs/api/README.md +60 -1
- package/docs/api/classes/ColumnFactory.md +1 -1
- package/docs/api/classes/ErrorBoundary.md +1 -1
- package/docs/api/classes/InvalidScopeError.md +1 -1
- package/docs/api/classes/Logger.md +178 -0
- package/docs/api/classes/MissingUserContextError.md +1 -1
- 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 +2 -2
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +5 -5
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/enums/LogLevel.md +54 -0
- package/docs/api/enums/RBACErrorCode.md +1 -1
- package/docs/api/enums/RPCFunction.md +1 -1
- package/docs/api/interfaces/AggregateConfig.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 +18 -2
- 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 +30 -0
- package/docs/api/interfaces/DataAccessRecord.md +1 -1
- 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 +85 -0
- package/docs/api/interfaces/DatabaseIssue.md +41 -0
- package/docs/api/interfaces/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
- package/docs/api/interfaces/EventAppRoleData.md +6 -6
- package/docs/api/interfaces/ExportColumn.md +1 -1
- package/docs/api/interfaces/ExportOptions.md +1 -1
- package/docs/api/interfaces/FileDisplayProps.md +1 -1
- package/docs/api/interfaces/FileMetadata.md +1 -1
- package/docs/api/interfaces/FileReference.md +1 -1
- package/docs/api/interfaces/FileSizeLimits.md +1 -1
- package/docs/api/interfaces/FileUploadOptions.md +24 -8
- package/docs/api/interfaces/FileUploadProps.md +24 -13
- 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 +9 -9
- 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 +62 -0
- package/docs/api/interfaces/LoginFormProps.md +1 -1
- package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
- package/docs/api/interfaces/NavigationContextType.md +1 -1
- 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 +1 -1
- 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 +36 -23
- package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
- package/docs/api/interfaces/PageAccessRecord.md +1 -1
- package/docs/api/interfaces/PagePermissionContextType.md +1 -1
- package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
- package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
- package/docs/api/interfaces/PaletteData.md +1 -1
- package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
- package/docs/api/interfaces/ProgressProps.md +1 -1
- 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 +52 -0
- 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 +4 -4
- 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/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 +7 -7
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RoleManagementResult.md +5 -5
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/RuntimeComplianceResult.md +55 -0
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
- package/docs/api/interfaces/SetupIssue.md +41 -0
- package/docs/api/interfaces/StorageConfig.md +1 -1
- package/docs/api/interfaces/StorageFileInfo.md +1 -1
- package/docs/api/interfaces/StorageFileMetadata.md +1 -1
- package/docs/api/interfaces/StorageListOptions.md +1 -1
- package/docs/api/interfaces/StorageListResult.md +1 -1
- package/docs/api/interfaces/StorageUploadOptions.md +1 -1
- package/docs/api/interfaces/StorageUploadResult.md +1 -1
- package/docs/api/interfaces/StorageUrlOptions.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
- package/docs/api/interfaces/UseFormDialogOptions.md +62 -0
- package/docs/api/interfaces/UseFormDialogReturn.md +117 -0
- 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 +2 -2
- package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
- package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
- package/docs/api/interfaces/UserEventAccess.md +1 -1
- package/docs/api/interfaces/UserMenuProps.md +1 -1
- package/docs/api/interfaces/UserProfile.md +1 -1
- package/docs/api/modules.md +738 -42
- package/docs/api-reference/hooks.md +111 -0
- package/docs/api-reference/rpc-functions.md +1 -1
- package/docs/api-reference/utilities.md +184 -0
- package/docs/getting-started/installation-guide.md +75 -16
- package/docs/getting-started/quick-start.md +61 -11
- package/docs/implementation-guides/authentication.md +88 -12
- package/docs/implementation-guides/file-reference-system.md +2 -1
- package/docs/implementation-guides/file-upload-storage.md +21 -0
- package/docs/rbac/README.md +1 -0
- package/docs/rbac/compliance/compliance-guide.md +544 -0
- package/docs/rbac/getting-started.md +158 -33
- package/docs/standards/pace-core-compliance.md +432 -0
- package/eslint-config-pace-core.cjs +93 -0
- package/package.json +15 -3
- package/scripts/analyze-bundle.js +232 -0
- package/scripts/build-css.js +56 -0
- package/scripts/build-docs-incremental.js +1015 -0
- package/scripts/check-pace-core-compliance.cjs +2353 -0
- package/scripts/generate-docs.js +157 -0
- package/scripts/setup-build-cache.js +73 -0
- package/scripts/utils/command-runner.js +131 -0
- package/scripts/utils/env.js +33 -0
- package/scripts/utils/index.js +10 -0
- package/scripts/utils/logger.js +88 -0
- package/scripts/utils/path-helpers.js +37 -0
- package/scripts/validate-formats.js +133 -0
- package/scripts/validate-master.js +155 -0
- package/scripts/validate-pre-publish.js +140 -0
- package/scripts/validate-theme.js +142 -0
- package/src/components/Calendar/Calendar.tsx +8 -1
- package/src/components/Card/Card.tsx +47 -8
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +314 -0
- package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +126 -0
- package/src/components/DatePickerWithTimezone/README.md +135 -0
- package/src/components/DatePickerWithTimezone/index.ts +10 -0
- package/src/components/DateTimeField/DateTimeField.test.tsx +358 -0
- package/src/components/DateTimeField/DateTimeField.tsx +232 -0
- package/src/components/DateTimeField/README.md +148 -0
- package/src/components/DateTimeField/index.ts +10 -0
- package/src/components/FileUpload/FileUpload.tsx +3 -0
- package/src/components/Header/Header.test.tsx +47 -18
- package/src/components/Header/Header.tsx +24 -6
- package/src/components/PaceAppLayout/PaceAppLayout.tsx +29 -20
- package/src/components/PaceAppLayout/README.md +9 -0
- package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
- package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +37 -8
- package/src/components/ProtectedRoute/ProtectedRoute.tsx +12 -4
- package/src/components/index.ts +8 -0
- package/src/eslint-rules/pace-core-compliance.cjs +406 -0
- package/src/eslint-rules/pace-core-compliance.js +640 -0
- package/src/hooks/__tests__/useFormDialog.test.ts +478 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useFileReference.test.ts +1 -0
- package/src/hooks/useFormDialog.ts +147 -0
- package/src/index.ts +27 -0
- package/src/providers/services/OrganisationServiceProvider.tsx +6 -5
- package/src/providers/services/UnifiedAuthProvider.tsx +24 -3
- package/src/rbac/__tests__/scenarios.user-role.test.tsx +3 -0
- package/src/rbac/compliance/database-validator.ts +165 -0
- package/src/rbac/compliance/index.ts +38 -0
- package/src/rbac/compliance/quick-fix-suggestions.ts +209 -0
- package/src/rbac/compliance/runtime-compliance.ts +77 -0
- package/src/rbac/compliance/setup-validator.ts +131 -0
- package/src/rbac/components/PagePermissionGuard.tsx +8 -64
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +35 -21
- package/src/rbac/docs/event-based-apps.md +285 -0
- package/src/rbac/errors.ts +11 -0
- package/src/rbac/hooks/useRoleManagement.ts +292 -12
- package/src/rbac/index.ts +30 -0
- package/src/services/OrganisationService.ts +4 -0
- package/src/types/file-reference.ts +6 -0
- package/src/utils/__tests__/timezone.test.ts +345 -0
- package/src/utils/file-reference/__tests__/file-reference.test.ts +2 -0
- package/src/utils/file-reference/index.ts +1 -0
- package/src/utils/formatting/formatDateTimeTimezone.test.ts +167 -0
- package/src/utils/formatting/formatting.ts +179 -0
- package/src/utils/index.ts +27 -1
- package/src/utils/location/index.ts +16 -0
- package/src/utils/location/location.test.ts +286 -0
- package/src/utils/location/location.ts +175 -0
- package/src/utils/timezone/index.ts +17 -0
- package/src/utils/timezone/timezone.test.ts +349 -0
- package/src/utils/timezone/timezone.ts +281 -0
- package/dist/chunk-CSOFYHAG.js.map +0 -1
- package/dist/chunk-FUEYYMX5.js.map +0 -1
- package/dist/chunk-HKIT6O7W.js +0 -198
- package/dist/chunk-HKIT6O7W.js.map +0 -1
- package/dist/chunk-KUEN3HFB.js +0 -94
- package/dist/chunk-KUEN3HFB.js.map +0 -1
- package/dist/chunk-M7W4CP3M.js.map +0 -1
- package/dist/chunk-PWAHJW4G.js.map +0 -1
- package/dist/chunk-QETLRQI6.js.map +0 -1
- package/dist/chunk-UHNYIBXL.js.map +0 -1
- package/dist/formatting-5wETwiGF.d.ts +0 -162
- /package/dist/{DataTable-QAB34V6K.js.map → DataTable-IX2NBUTP.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-7F6T4B6K.js.map → UnifiedAuthProvider-A4BCQRJY.js.map} +0 -0
- /package/dist/{api-ROMBCNKU.js.map → api-BMFCXVQX.js.map} +0 -0
- /package/dist/{chunk-W22JP75J.js.map → chunk-STTZQK2I.js.map} +0 -0
- /package/dist/{chunk-QCDXODCA.js.map → chunk-XAUHJD3L.js.map} +0 -0
package/src/rbac/errors.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
OrganisationContextRequiredError,
|
|
5
5
|
InvalidScopeError,
|
|
6
6
|
MissingUserContextError,
|
|
7
|
+
RBACNotInitializedError,
|
|
7
8
|
} from './types';
|
|
8
9
|
|
|
9
10
|
export enum RBACErrorCategory {
|
|
@@ -154,3 +155,13 @@ export function mapErrorCategoryToSecurityEventType(category: RBACErrorCategory)
|
|
|
154
155
|
return 'unknown_error';
|
|
155
156
|
}
|
|
156
157
|
}
|
|
158
|
+
|
|
159
|
+
// Re-export error classes for convenience
|
|
160
|
+
export {
|
|
161
|
+
RBACError,
|
|
162
|
+
PermissionDeniedError,
|
|
163
|
+
OrganisationContextRequiredError,
|
|
164
|
+
InvalidScopeError,
|
|
165
|
+
MissingUserContextError,
|
|
166
|
+
RBACNotInitializedError,
|
|
167
|
+
};
|
|
@@ -13,25 +13,46 @@
|
|
|
13
13
|
* import { useRoleManagement } from '@jmruthers/pace-core/rbac';
|
|
14
14
|
*
|
|
15
15
|
* function UserRolesComponent() {
|
|
16
|
-
* const {
|
|
16
|
+
* const {
|
|
17
|
+
* revokeEventAppRole,
|
|
18
|
+
* grantEventAppRole,
|
|
19
|
+
* grantGlobalRole,
|
|
20
|
+
* revokeGlobalRole,
|
|
21
|
+
* grantOrganisationRole,
|
|
22
|
+
* revokeOrganisationRole,
|
|
23
|
+
* isLoading,
|
|
24
|
+
* error
|
|
25
|
+
* } = useRoleManagement();
|
|
17
26
|
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
20
|
-
*
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
* appId: roleData.app_id,
|
|
24
|
-
* role: roleData.role
|
|
27
|
+
* // Grant a global role
|
|
28
|
+
* const handleGrantGlobalRole = async () => {
|
|
29
|
+
* const result = await grantGlobalRole({
|
|
30
|
+
* user_id: userId,
|
|
31
|
+
* role: 'super_admin'
|
|
25
32
|
* });
|
|
33
|
+
* if (result.success) {
|
|
34
|
+
* toast({ title: 'Role granted successfully' });
|
|
35
|
+
* }
|
|
36
|
+
* };
|
|
26
37
|
*
|
|
38
|
+
* // Grant an organisation role
|
|
39
|
+
* const handleGrantOrgRole = async () => {
|
|
40
|
+
* const result = await grantOrganisationRole({
|
|
41
|
+
* user_id: userId,
|
|
42
|
+
* organisation_id: orgId,
|
|
43
|
+
* role: 'org_admin'
|
|
44
|
+
* });
|
|
27
45
|
* if (result.success) {
|
|
28
|
-
* toast({ title: 'Role
|
|
29
|
-
* } else {
|
|
30
|
-
* toast({ title: 'Failed to revoke role', variant: 'destructive' });
|
|
46
|
+
* toast({ title: 'Role granted successfully' });
|
|
31
47
|
* }
|
|
32
48
|
* };
|
|
33
49
|
*
|
|
34
|
-
* return
|
|
50
|
+
* return (
|
|
51
|
+
* <div>
|
|
52
|
+
* <button onClick={handleGrantGlobalRole}>Grant Super Admin</button>
|
|
53
|
+
* <button onClick={handleGrantOrgRole}>Grant Org Admin</button>
|
|
54
|
+
* </div>
|
|
55
|
+
* );
|
|
35
56
|
* }
|
|
36
57
|
* ```
|
|
37
58
|
*/
|
|
@@ -48,6 +69,17 @@ export interface EventAppRoleData {
|
|
|
48
69
|
role: 'viewer' | 'participant' | 'planner' | 'event_admin';
|
|
49
70
|
}
|
|
50
71
|
|
|
72
|
+
export interface OrganisationRoleData {
|
|
73
|
+
user_id: UUID;
|
|
74
|
+
organisation_id: UUID;
|
|
75
|
+
role: 'supporter' | 'member' | 'leader' | 'org_admin';
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export interface GlobalRoleData {
|
|
79
|
+
user_id: UUID;
|
|
80
|
+
role: 'super_admin';
|
|
81
|
+
}
|
|
82
|
+
|
|
51
83
|
export interface RevokeEventAppRoleParams extends EventAppRoleData {
|
|
52
84
|
revoked_by?: UUID;
|
|
53
85
|
}
|
|
@@ -58,6 +90,26 @@ export interface GrantEventAppRoleParams extends EventAppRoleData {
|
|
|
58
90
|
valid_to?: string | null;
|
|
59
91
|
}
|
|
60
92
|
|
|
93
|
+
export interface RevokeOrganisationRoleParams extends OrganisationRoleData {
|
|
94
|
+
revoked_by?: UUID;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export interface GrantOrganisationRoleParams extends OrganisationRoleData {
|
|
98
|
+
granted_by?: UUID;
|
|
99
|
+
valid_from?: string;
|
|
100
|
+
valid_to?: string | null;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface RevokeGlobalRoleParams extends GlobalRoleData {
|
|
104
|
+
revoked_by?: UUID;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export interface GrantGlobalRoleParams extends GlobalRoleData {
|
|
108
|
+
granted_by?: UUID;
|
|
109
|
+
valid_from?: string;
|
|
110
|
+
valid_to?: string | null;
|
|
111
|
+
}
|
|
112
|
+
|
|
61
113
|
export interface RoleManagementResult {
|
|
62
114
|
success: boolean;
|
|
63
115
|
message?: string;
|
|
@@ -244,10 +296,238 @@ export function useRoleManagement() {
|
|
|
244
296
|
}
|
|
245
297
|
}, [user?.id, supabase]);
|
|
246
298
|
|
|
299
|
+
/**
|
|
300
|
+
* Grant a global role using the unified RPC function
|
|
301
|
+
*
|
|
302
|
+
* This function uses the `rbac_role_grant` RPC which:
|
|
303
|
+
* - Runs with SECURITY DEFINER privileges
|
|
304
|
+
* - Includes proper permission checks
|
|
305
|
+
* - Automatically populates audit fields (granted_by, timestamps)
|
|
306
|
+
* - Complies with Row-Level Security policies
|
|
307
|
+
*
|
|
308
|
+
* @param params - Role grant parameters
|
|
309
|
+
* @returns Promise resolving to operation result with role ID
|
|
310
|
+
*/
|
|
311
|
+
const grantGlobalRole = useCallback(async (
|
|
312
|
+
params: GrantGlobalRoleParams
|
|
313
|
+
): Promise<RoleManagementResult> => {
|
|
314
|
+
setIsLoading(true);
|
|
315
|
+
setError(null);
|
|
316
|
+
|
|
317
|
+
try {
|
|
318
|
+
const { data, error: rpcError } = await supabase.rpc('rbac_role_grant', {
|
|
319
|
+
p_user_id: params.user_id,
|
|
320
|
+
p_role_type: 'global',
|
|
321
|
+
p_role_name: params.role,
|
|
322
|
+
p_context_id: null, // Global roles don't need context
|
|
323
|
+
p_granted_by: params.granted_by || user?.id || undefined
|
|
324
|
+
});
|
|
325
|
+
|
|
326
|
+
if (rpcError) {
|
|
327
|
+
throw new Error(rpcError.message || 'Failed to grant role');
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// rbac_role_grant returns a table with success, message, role_id, error_code
|
|
331
|
+
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
332
|
+
|
|
333
|
+
if (!result || !result.success) {
|
|
334
|
+
return {
|
|
335
|
+
success: false,
|
|
336
|
+
error: result?.message || result?.error_code || 'Failed to grant role',
|
|
337
|
+
message: result?.message
|
|
338
|
+
};
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return {
|
|
342
|
+
success: true,
|
|
343
|
+
message: result.message || 'Role granted successfully',
|
|
344
|
+
roleId: result.role_id
|
|
345
|
+
};
|
|
346
|
+
} catch (err) {
|
|
347
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
348
|
+
setError(err instanceof Error ? err : new Error(errorMessage));
|
|
349
|
+
return {
|
|
350
|
+
success: false,
|
|
351
|
+
error: errorMessage
|
|
352
|
+
};
|
|
353
|
+
} finally {
|
|
354
|
+
setIsLoading(false);
|
|
355
|
+
}
|
|
356
|
+
}, [user?.id, supabase]);
|
|
357
|
+
|
|
358
|
+
/**
|
|
359
|
+
* Revoke a global role using the unified RPC function
|
|
360
|
+
*
|
|
361
|
+
* This function uses the `rbac_role_revoke` RPC which:
|
|
362
|
+
* - Runs with SECURITY DEFINER privileges
|
|
363
|
+
* - Includes proper permission checks
|
|
364
|
+
* - Automatically populates audit fields (revoked_by, timestamps)
|
|
365
|
+
* - Complies with Row-Level Security policies
|
|
366
|
+
*
|
|
367
|
+
* @param params - Role revocation parameters
|
|
368
|
+
* @returns Promise resolving to operation result
|
|
369
|
+
*/
|
|
370
|
+
const revokeGlobalRole = useCallback(async (
|
|
371
|
+
params: RevokeGlobalRoleParams
|
|
372
|
+
): Promise<RoleManagementResult> => {
|
|
373
|
+
setIsLoading(true);
|
|
374
|
+
setError(null);
|
|
375
|
+
|
|
376
|
+
try {
|
|
377
|
+
const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', {
|
|
378
|
+
p_user_id: params.user_id,
|
|
379
|
+
p_role_type: 'global',
|
|
380
|
+
p_role_name: params.role,
|
|
381
|
+
p_context_id: null, // Global roles don't need context
|
|
382
|
+
p_revoked_by: params.revoked_by || user?.id || undefined
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
if (rpcError) {
|
|
386
|
+
throw new Error(rpcError.message || 'Failed to revoke role');
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
// rbac_role_revoke returns a table with success, message, revoked_count, error_code
|
|
390
|
+
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
391
|
+
|
|
392
|
+
return {
|
|
393
|
+
success: result?.success === true,
|
|
394
|
+
message: result?.message || undefined,
|
|
395
|
+
error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined
|
|
396
|
+
};
|
|
397
|
+
} catch (err) {
|
|
398
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
399
|
+
setError(err instanceof Error ? err : new Error(errorMessage));
|
|
400
|
+
return {
|
|
401
|
+
success: false,
|
|
402
|
+
error: errorMessage
|
|
403
|
+
};
|
|
404
|
+
} finally {
|
|
405
|
+
setIsLoading(false);
|
|
406
|
+
}
|
|
407
|
+
}, [user?.id, supabase]);
|
|
408
|
+
|
|
409
|
+
/**
|
|
410
|
+
* Grant an organisation role using the unified RPC function
|
|
411
|
+
*
|
|
412
|
+
* This function uses the `rbac_role_grant` RPC which:
|
|
413
|
+
* - Runs with SECURITY DEFINER privileges
|
|
414
|
+
* - Includes proper permission checks
|
|
415
|
+
* - Automatically populates audit fields (granted_by, timestamps)
|
|
416
|
+
* - Complies with Row-Level Security policies
|
|
417
|
+
*
|
|
418
|
+
* @param params - Role grant parameters
|
|
419
|
+
* @returns Promise resolving to operation result with role ID
|
|
420
|
+
*/
|
|
421
|
+
const grantOrganisationRole = useCallback(async (
|
|
422
|
+
params: GrantOrganisationRoleParams
|
|
423
|
+
): Promise<RoleManagementResult> => {
|
|
424
|
+
setIsLoading(true);
|
|
425
|
+
setError(null);
|
|
426
|
+
|
|
427
|
+
try {
|
|
428
|
+
const { data, error: rpcError } = await supabase.rpc('rbac_role_grant', {
|
|
429
|
+
p_user_id: params.user_id,
|
|
430
|
+
p_role_type: 'organisation',
|
|
431
|
+
p_role_name: params.role,
|
|
432
|
+
p_context_id: params.organisation_id, // Organisation ID as context
|
|
433
|
+
p_granted_by: params.granted_by || user?.id || undefined
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
if (rpcError) {
|
|
437
|
+
throw new Error(rpcError.message || 'Failed to grant role');
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// rbac_role_grant returns a table with success, message, role_id, error_code
|
|
441
|
+
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
442
|
+
|
|
443
|
+
if (!result || !result.success) {
|
|
444
|
+
return {
|
|
445
|
+
success: false,
|
|
446
|
+
error: result?.message || result?.error_code || 'Failed to grant role',
|
|
447
|
+
message: result?.message
|
|
448
|
+
};
|
|
449
|
+
}
|
|
450
|
+
|
|
451
|
+
return {
|
|
452
|
+
success: true,
|
|
453
|
+
message: result.message || 'Role granted successfully',
|
|
454
|
+
roleId: result.role_id
|
|
455
|
+
};
|
|
456
|
+
} catch (err) {
|
|
457
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
458
|
+
setError(err instanceof Error ? err : new Error(errorMessage));
|
|
459
|
+
return {
|
|
460
|
+
success: false,
|
|
461
|
+
error: errorMessage
|
|
462
|
+
};
|
|
463
|
+
} finally {
|
|
464
|
+
setIsLoading(false);
|
|
465
|
+
}
|
|
466
|
+
}, [user?.id, supabase]);
|
|
467
|
+
|
|
468
|
+
/**
|
|
469
|
+
* Revoke an organisation role using the unified RPC function
|
|
470
|
+
*
|
|
471
|
+
* This function uses the `rbac_role_revoke` RPC which:
|
|
472
|
+
* - Runs with SECURITY DEFINER privileges
|
|
473
|
+
* - Includes proper permission checks
|
|
474
|
+
* - Automatically populates audit fields (revoked_by, timestamps)
|
|
475
|
+
* - Complies with Row-Level Security policies
|
|
476
|
+
*
|
|
477
|
+
* @param params - Role revocation parameters
|
|
478
|
+
* @returns Promise resolving to operation result
|
|
479
|
+
*/
|
|
480
|
+
const revokeOrganisationRole = useCallback(async (
|
|
481
|
+
params: RevokeOrganisationRoleParams
|
|
482
|
+
): Promise<RoleManagementResult> => {
|
|
483
|
+
setIsLoading(true);
|
|
484
|
+
setError(null);
|
|
485
|
+
|
|
486
|
+
try {
|
|
487
|
+
const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', {
|
|
488
|
+
p_user_id: params.user_id,
|
|
489
|
+
p_role_type: 'organisation',
|
|
490
|
+
p_role_name: params.role,
|
|
491
|
+
p_context_id: params.organisation_id, // Organisation ID as context
|
|
492
|
+
p_revoked_by: params.revoked_by || user?.id || undefined
|
|
493
|
+
});
|
|
494
|
+
|
|
495
|
+
if (rpcError) {
|
|
496
|
+
throw new Error(rpcError.message || 'Failed to revoke role');
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
// rbac_role_revoke returns a table with success, message, revoked_count, error_code
|
|
500
|
+
const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
|
|
501
|
+
|
|
502
|
+
return {
|
|
503
|
+
success: result?.success === true,
|
|
504
|
+
message: result?.message || undefined,
|
|
505
|
+
error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined
|
|
506
|
+
};
|
|
507
|
+
} catch (err) {
|
|
508
|
+
const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
|
|
509
|
+
setError(err instanceof Error ? err : new Error(errorMessage));
|
|
510
|
+
return {
|
|
511
|
+
success: false,
|
|
512
|
+
error: errorMessage
|
|
513
|
+
};
|
|
514
|
+
} finally {
|
|
515
|
+
setIsLoading(false);
|
|
516
|
+
}
|
|
517
|
+
}, [user?.id, supabase]);
|
|
518
|
+
|
|
247
519
|
return {
|
|
520
|
+
// Event app roles (existing)
|
|
248
521
|
revokeEventAppRole,
|
|
249
522
|
grantEventAppRole,
|
|
250
523
|
revokeRoleById,
|
|
524
|
+
// Global roles (new)
|
|
525
|
+
grantGlobalRole,
|
|
526
|
+
revokeGlobalRole,
|
|
527
|
+
// Organisation roles (new)
|
|
528
|
+
grantOrganisationRole,
|
|
529
|
+
revokeOrganisationRole,
|
|
530
|
+
// Shared state
|
|
251
531
|
isLoading,
|
|
252
532
|
error
|
|
253
533
|
};
|
package/src/rbac/index.ts
CHANGED
|
@@ -113,3 +113,33 @@ export {
|
|
|
113
113
|
|
|
114
114
|
// Permissions
|
|
115
115
|
export * from './permissions';
|
|
116
|
+
|
|
117
|
+
// Compliance
|
|
118
|
+
export {
|
|
119
|
+
isRBACInitialized,
|
|
120
|
+
validateRBACSetup,
|
|
121
|
+
getSetupIssues,
|
|
122
|
+
type SetupIssue,
|
|
123
|
+
type ComplianceResult,
|
|
124
|
+
} from './compliance/setup-validator';
|
|
125
|
+
|
|
126
|
+
export {
|
|
127
|
+
checkRuntimeCompliance,
|
|
128
|
+
validateAndWarn,
|
|
129
|
+
type RuntimeComplianceResult,
|
|
130
|
+
} from './compliance/runtime-compliance';
|
|
131
|
+
|
|
132
|
+
export {
|
|
133
|
+
validateDatabaseConfiguration,
|
|
134
|
+
type DatabaseComplianceResult,
|
|
135
|
+
type DatabaseIssue,
|
|
136
|
+
} from './compliance/database-validator';
|
|
137
|
+
|
|
138
|
+
export {
|
|
139
|
+
getQuickFixes,
|
|
140
|
+
getCustomAuthCodeFixes,
|
|
141
|
+
getDuplicateConfigFixes,
|
|
142
|
+
getUnprotectedPageFixes,
|
|
143
|
+
getDirectSupabaseAuthFixes,
|
|
144
|
+
type QuickFix,
|
|
145
|
+
} from './compliance/quick-fix-suggestions';
|
|
@@ -519,6 +519,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
519
519
|
|
|
520
520
|
// Auto-select organisation: try persisted, then primary, then first
|
|
521
521
|
let initialOrg: Organisation | null = null;
|
|
522
|
+
let selectionMethod: 'persisted' | 'admin' | 'first' = 'first';
|
|
522
523
|
|
|
523
524
|
// 1. Try to restore from localStorage
|
|
524
525
|
try {
|
|
@@ -530,6 +531,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
530
531
|
const validPersistedOrg = activeOrgs.find(org => org.id === persistedOrg.id);
|
|
531
532
|
if (validPersistedOrg) {
|
|
532
533
|
initialOrg = validPersistedOrg;
|
|
534
|
+
selectionMethod = 'persisted';
|
|
533
535
|
} else {
|
|
534
536
|
logger.warn("OrganisationService", "Persisted organisation not found in active orgs, clearing cache");
|
|
535
537
|
localStorage.removeItem('pace-core-selected-organisation');
|
|
@@ -552,6 +554,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
552
554
|
const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
|
|
553
555
|
if (foundOrg) {
|
|
554
556
|
initialOrg = foundOrg;
|
|
557
|
+
selectionMethod = 'admin';
|
|
555
558
|
}
|
|
556
559
|
}
|
|
557
560
|
}
|
|
@@ -559,6 +562,7 @@ export class OrganisationService extends BaseService implements IOrganisationSer
|
|
|
559
562
|
// 3. Fall back to first organisation
|
|
560
563
|
if (!initialOrg) {
|
|
561
564
|
initialOrg = activeOrgs[0];
|
|
565
|
+
selectionMethod = 'first';
|
|
562
566
|
}
|
|
563
567
|
|
|
564
568
|
if (!initialOrg) {
|
|
@@ -51,12 +51,18 @@ export enum FileCategory {
|
|
|
51
51
|
TRAC_TRANSPORT = 'trac_transport'
|
|
52
52
|
}
|
|
53
53
|
|
|
54
|
+
/**
|
|
55
|
+
* Options for uploading a file with a file reference
|
|
56
|
+
* @property pageContext - The page context where the file upload occurs (e.g., 'configuration', 'forms', 'applications')
|
|
57
|
+
* Used for context-aware permission checks. Required to check appropriate page-level permissions.
|
|
58
|
+
*/
|
|
54
59
|
export interface FileUploadOptions {
|
|
55
60
|
table_name: string;
|
|
56
61
|
record_id: string;
|
|
57
62
|
organisation_id: string;
|
|
58
63
|
app_id: AppId;
|
|
59
64
|
category: FileCategory;
|
|
65
|
+
pageContext: string;
|
|
60
66
|
is_public?: boolean;
|
|
61
67
|
custom_metadata?: Record<string, unknown>;
|
|
62
68
|
}
|