@jmruthers/pace-core 0.5.109 → 0.5.110
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 +22 -0
- package/dist/{DataTable-5HITILXS.js → DataTable-D3BK2FCN.js} +4 -4
- package/dist/{api-5I3E47G2.js → api-PIE4JRFS.js} +2 -2
- package/dist/{chunk-P72NKAT5.js → chunk-3J5N2T2N.js} +51 -11
- package/dist/chunk-3J5N2T2N.js.map +1 -0
- package/dist/{chunk-3TKTL5AZ.js → chunk-7GBEBJLR.js} +26 -34
- package/dist/chunk-7GBEBJLR.js.map +1 -0
- package/dist/{chunk-S4D3Z723.js → chunk-AWK2FAUN.js} +3 -3
- package/dist/{chunk-WWNOVFDC.js → chunk-HADXAZT3.js} +2 -2
- package/dist/{chunk-UW2DE6JX.js → chunk-HGZSO43Y.js} +2 -2
- package/dist/{chunk-F6TSYCKP.js → chunk-XRSP3H52.js} +12 -7
- package/dist/chunk-XRSP3H52.js.map +1 -0
- package/dist/components.js +4 -4
- package/dist/hooks.js +1 -1
- package/dist/index.js +6 -6
- package/dist/rbac/index.d.ts +34 -22
- package/dist/rbac/index.js +3 -3
- package/dist/utils.js +1 -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/MissingUserContextError.md +1 -1
- package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
- package/docs/api/classes/PermissionDeniedError.md +1 -1
- package/docs/api/classes/PublicErrorBoundary.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 +9 -8
- package/docs/api/classes/RBACError.md +1 -1
- package/docs/api/classes/RBACNotInitializedError.md +1 -1
- package/docs/api/classes/SecureSupabaseClient.md +1 -1
- package/docs/api/classes/StorageUtils.md +1 -1
- package/docs/api/enums/FileCategory.md +1 -1
- package/docs/api/interfaces/AggregateConfig.md +1 -1
- package/docs/api/interfaces/ButtonProps.md +1 -1
- 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/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/EmptyStateConfig.md +1 -1
- package/docs/api/interfaces/EnhancedNavigationMenuProps.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 +1 -1
- package/docs/api/interfaces/FileUploadProps.md +1 -1
- package/docs/api/interfaces/FooterProps.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/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 +1 -1
- 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 +1 -1
- 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/ProtectedRouteProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
- package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
- package/docs/api/interfaces/PublicLoadingSpinnerProps.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/RBACConfig.md +19 -8
- package/docs/api/interfaces/RBACLogger.md +5 -5
- package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
- package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
- package/docs/api/interfaces/RouteAccessRecord.md +1 -1
- package/docs/api/interfaces/RouteConfig.md +1 -1
- package/docs/api/interfaces/SecureDataContextType.md +1 -1
- package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
- 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/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/UseInactivityTrackerOptions.md +1 -1
- package/docs/api/interfaces/UseInactivityTrackerReturn.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 +1 -1
- package/docs/api/interfaces/UseResolvedScopeReturn.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 +21 -20
- package/docs/documentation-index.md +0 -2
- package/docs/rbac/README.md +114 -38
- package/docs/rbac/api-reference.md +63 -16
- package/docs/rbac/getting-started.md +16 -16
- package/docs/rbac/quick-start.md +110 -35
- package/docs/rbac/troubleshooting.md +125 -2
- package/package.json +1 -1
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +38 -4
- package/src/components/NavigationMenu/NavigationMenu.tsx +71 -6
- package/src/rbac/api.test.ts +2 -2
- package/src/rbac/api.ts +2 -1
- package/src/rbac/components/PagePermissionGuard.tsx +21 -38
- package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +1 -1
- package/src/rbac/config.ts +2 -0
- package/src/rbac/engine.ts +15 -5
- package/src/rbac/security.ts +1 -1
- package/dist/chunk-3TKTL5AZ.js.map +0 -1
- package/dist/chunk-F6TSYCKP.js.map +0 -1
- package/dist/chunk-P72NKAT5.js.map +0 -1
- package/docs/rbac/breaking-changes-v3.md +0 -222
- package/docs/rbac/migration-guide.md +0 -260
- /package/dist/{DataTable-5HITILXS.js.map → DataTable-D3BK2FCN.js.map} +0 -0
- /package/dist/{api-5I3E47G2.js.map → api-PIE4JRFS.js.map} +0 -0
- /package/dist/{chunk-S4D3Z723.js.map → chunk-AWK2FAUN.js.map} +0 -0
- /package/dist/{chunk-WWNOVFDC.js.map → chunk-HADXAZT3.js.map} +0 -0
- /package/dist/{chunk-UW2DE6JX.js.map → chunk-HGZSO43Y.js.map} +0 -0
|
@@ -462,10 +462,16 @@ export const NavigationMenu = React.forwardRef<
|
|
|
462
462
|
return (items || []).filter(item => !item.meta?.hidden);
|
|
463
463
|
}
|
|
464
464
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
if (
|
|
468
|
-
|
|
465
|
+
// Helper function to derive page ID from href
|
|
466
|
+
const getPageIdFromHref = (href?: string): string | null => {
|
|
467
|
+
if (!href) return null;
|
|
468
|
+
// Remove leading slash and any query params/hash
|
|
469
|
+
const path = href.split('?')[0].split('#')[0].replace(/^\//, '');
|
|
470
|
+
return path || 'home';
|
|
471
|
+
};
|
|
472
|
+
|
|
473
|
+
// Helper function to check if item has permission to be shown
|
|
474
|
+
const hasItemPermission = (item: NavigationItem): boolean => {
|
|
469
475
|
// Check permissions if available
|
|
470
476
|
if (item.permissions && item.permissions.length > 0) {
|
|
471
477
|
// Convert string permissions to Permission type and check
|
|
@@ -547,8 +553,66 @@ export const NavigationMenu = React.forwardRef<
|
|
|
547
553
|
}
|
|
548
554
|
}
|
|
549
555
|
|
|
556
|
+
// NEW: Auto-check page permissions for items with href but no explicit permissions
|
|
557
|
+
// If item has an href but no explicit permissions/roles/accessLevel, check page permission
|
|
558
|
+
if (item.href && !item.permissions && !item.roles && !item.accessLevel) {
|
|
559
|
+
const pageId = item.pageId || getPageIdFromHref(item.href);
|
|
560
|
+
if (pageId) {
|
|
561
|
+
// Check for read permission on the page
|
|
562
|
+
const pagePermission: Permission = `read:page.${pageId}` as Permission;
|
|
563
|
+
|
|
564
|
+
// Check permission map (super admin has access to everything via '*' key)
|
|
565
|
+
const hasPagePermission = permissionMap['*'] === true || permissionMap[pagePermission] === true;
|
|
566
|
+
|
|
567
|
+
if (!hasPagePermission) {
|
|
568
|
+
if (auditLog) {
|
|
569
|
+
console.log(`[NavigationMenu] Filtering out navigation item "${item.label}" - no page permission:`, {
|
|
570
|
+
itemId: item.id,
|
|
571
|
+
href: item.href,
|
|
572
|
+
pageId,
|
|
573
|
+
permission: pagePermission,
|
|
574
|
+
hasPermission: hasPagePermission
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
return false;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
|
|
550
582
|
return true;
|
|
551
|
-
}
|
|
583
|
+
};
|
|
584
|
+
|
|
585
|
+
// Helper function to filter items recursively (creates new objects to avoid mutations)
|
|
586
|
+
const filterItem = (item: NavigationItem): NavigationItem | null => {
|
|
587
|
+
// Check if item should be hidden
|
|
588
|
+
if (item.meta?.hidden) return null;
|
|
589
|
+
|
|
590
|
+
// Check if item has permission
|
|
591
|
+
if (!hasItemPermission(item)) return null;
|
|
592
|
+
|
|
593
|
+
// Recursively filter children if present
|
|
594
|
+
let filteredChildren: NavigationItem[] | undefined;
|
|
595
|
+
if (item.children && item.children.length > 0) {
|
|
596
|
+
filteredChildren = item.children
|
|
597
|
+
.map(child => filterItem(child))
|
|
598
|
+
.filter((child): child is NavigationItem => child !== null);
|
|
599
|
+
|
|
600
|
+
// If parent has no accessible children, hide the parent too (unless it has its own href)
|
|
601
|
+
if (filteredChildren.length === 0 && !item.href) {
|
|
602
|
+
return null;
|
|
603
|
+
}
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
// Return filtered item (with filtered children if applicable)
|
|
607
|
+
return {
|
|
608
|
+
...item,
|
|
609
|
+
children: filteredChildren
|
|
610
|
+
};
|
|
611
|
+
};
|
|
612
|
+
|
|
613
|
+
return (items || [])
|
|
614
|
+
.map(item => filterItem(item))
|
|
615
|
+
.filter((item): item is NavigationItem => item !== null);
|
|
552
616
|
}, [
|
|
553
617
|
items,
|
|
554
618
|
filterByPermissions,
|
|
@@ -558,7 +622,8 @@ export const NavigationMenu = React.forwardRef<
|
|
|
558
622
|
hasAnyPermission,
|
|
559
623
|
scopeLoading,
|
|
560
624
|
permissionsLoading,
|
|
561
|
-
resolvedScope
|
|
625
|
+
resolvedScope,
|
|
626
|
+
auditLog
|
|
562
627
|
]);
|
|
563
628
|
|
|
564
629
|
// Log navigation access attempts for debugging
|
package/src/rbac/api.test.ts
CHANGED
|
@@ -119,7 +119,7 @@ describe('RBAC API', () => {
|
|
|
119
119
|
|
|
120
120
|
process.env.NODE_ENV = originalEnv;
|
|
121
121
|
|
|
122
|
-
expect(mockCreateRBACEngine).toHaveBeenCalledWith(mockSupabase);
|
|
122
|
+
expect(mockCreateRBACEngine).toHaveBeenCalledWith(mockSupabase, undefined);
|
|
123
123
|
expect(mockCreateAuditManager).toHaveBeenCalledWith(mockSupabase);
|
|
124
124
|
expect(mockSetGlobalAuditManager).toHaveBeenCalledWith(mockAuditManager);
|
|
125
125
|
expect(mockLogger.info).toHaveBeenCalledWith('RBAC system initialized successfully');
|
|
@@ -203,7 +203,7 @@ describe('RBAC API', () => {
|
|
|
203
203
|
|
|
204
204
|
setupRBAC(mockSupabase as any);
|
|
205
205
|
|
|
206
|
-
expect(mockCreateRBACEngine).toHaveBeenCalledWith(mockSupabase);
|
|
206
|
+
expect(mockCreateRBACEngine).toHaveBeenCalledWith(mockSupabase, undefined);
|
|
207
207
|
});
|
|
208
208
|
|
|
209
209
|
it('handles multiple initialization calls', () => {
|
package/src/rbac/api.ts
CHANGED
|
@@ -49,7 +49,8 @@ export function setupRBAC(supabase: SupabaseClient<Database>, config?: Partial<R
|
|
|
49
49
|
|
|
50
50
|
createRBACConfig(fullConfig);
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
// Pass security config to engine if provided
|
|
53
|
+
globalEngine = createRBACEngine(supabase, config?.security);
|
|
53
54
|
|
|
54
55
|
// Setup audit manager
|
|
55
56
|
const auditManager = createAuditManager(supabase);
|
|
@@ -148,41 +148,6 @@ const PagePermissionGuardComponent = ({
|
|
|
148
148
|
const supabaseRef = useRef(supabase);
|
|
149
149
|
supabaseRef.current = supabase;
|
|
150
150
|
|
|
151
|
-
// Track the last scope we called useCan with to prevent infinite loops
|
|
152
|
-
const lastScopeRef = useRef<string | null>(null);
|
|
153
|
-
|
|
154
|
-
// Use a ref to store the stable scope and only update it when it actually changes
|
|
155
|
-
const stableScopeRef = useRef<{ organisationId: string; appId: string; eventId: string | undefined }>({
|
|
156
|
-
organisationId: '',
|
|
157
|
-
appId: '',
|
|
158
|
-
eventId: undefined
|
|
159
|
-
});
|
|
160
|
-
|
|
161
|
-
// Only update the stable scope if the resolved scope has actually changed
|
|
162
|
-
if (resolvedScope && resolvedScope.organisationId) {
|
|
163
|
-
const newScope = {
|
|
164
|
-
organisationId: resolvedScope.organisationId,
|
|
165
|
-
appId: resolvedScope.appId,
|
|
166
|
-
eventId: resolvedScope.eventId
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
// Only update if the scope has actually changed
|
|
170
|
-
if (stableScopeRef.current.organisationId !== newScope.organisationId ||
|
|
171
|
-
stableScopeRef.current.eventId !== newScope.eventId ||
|
|
172
|
-
stableScopeRef.current.appId !== newScope.appId) {
|
|
173
|
-
stableScopeRef.current = {
|
|
174
|
-
organisationId: newScope.organisationId,
|
|
175
|
-
appId: newScope.appId || '',
|
|
176
|
-
eventId: newScope.eventId
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
} else if (!resolvedScope) {
|
|
180
|
-
// Reset to empty scope when no resolved scope
|
|
181
|
-
stableScopeRef.current = { organisationId: '', appId: '', eventId: undefined };
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
const stableScope = stableScopeRef.current;
|
|
185
|
-
|
|
186
151
|
// Resolve scope - either use provided scope or resolve from context
|
|
187
152
|
useEffect(() => {
|
|
188
153
|
const abortController = new AbortController();
|
|
@@ -412,9 +377,22 @@ const PagePermissionGuardComponent = ({
|
|
|
412
377
|
return `${operation}:page.${pageName}` as Permission;
|
|
413
378
|
}, [operation, pageName]);
|
|
414
379
|
|
|
380
|
+
// Create a stable scope that only includes valid values
|
|
381
|
+
// This ensures useCan doesn't run with empty organisationId which causes it to stay in loading state
|
|
382
|
+
const stableScope = useMemo(() => {
|
|
383
|
+
if (resolvedScope && resolvedScope.organisationId) {
|
|
384
|
+
return {
|
|
385
|
+
organisationId: resolvedScope.organisationId,
|
|
386
|
+
appId: resolvedScope.appId || undefined,
|
|
387
|
+
eventId: resolvedScope.eventId || undefined
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
// Return a scope with empty string organisationId - useCan will handle this by keeping loading state
|
|
391
|
+
return { organisationId: '', appId: undefined, eventId: undefined };
|
|
392
|
+
}, [resolvedScope]);
|
|
415
393
|
|
|
416
|
-
// Check if user has permission - only call useCan when we have a resolved scope
|
|
417
|
-
// If resolvedScope is null
|
|
394
|
+
// Check if user has permission - only call useCan when we have a resolved scope with valid organisationId
|
|
395
|
+
// If resolvedScope is null or has no organisationId, useCan will keep isLoading=true
|
|
418
396
|
const { can, isLoading: canIsLoading, error: canError } = useCan(
|
|
419
397
|
user?.id || '',
|
|
420
398
|
stableScope,
|
|
@@ -464,12 +442,17 @@ const PagePermissionGuardComponent = ({
|
|
|
464
442
|
console.error(`[PagePermissionGuard] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
|
|
465
443
|
pageName,
|
|
466
444
|
operation,
|
|
445
|
+
permission: `${operation}:page.${pageName}`,
|
|
446
|
+
pageId: effectivePageId,
|
|
467
447
|
userId: user?.id,
|
|
468
448
|
scope: resolvedScope,
|
|
449
|
+
scopeValid: resolvedScope && resolvedScope.organisationId ? true : false,
|
|
450
|
+
checkError,
|
|
451
|
+
canError,
|
|
469
452
|
timestamp: new Date().toISOString()
|
|
470
453
|
});
|
|
471
454
|
}
|
|
472
|
-
}, [strictMode, hasChecked, isLoading, can, pageName, operation, user?.id, resolvedScope]);
|
|
455
|
+
}, [strictMode, hasChecked, isLoading, can, pageName, operation, effectivePageId, user?.id, resolvedScope, checkError, canError]);
|
|
473
456
|
|
|
474
457
|
// Calculate the actual render state - FIXED: Proper state calculation
|
|
475
458
|
// Add defensive checks to ensure we have valid state
|
|
@@ -949,7 +949,7 @@ describe('PagePermissionGuard Component', () => {
|
|
|
949
949
|
expect.objectContaining({
|
|
950
950
|
organisationId: '',
|
|
951
951
|
eventId: undefined,
|
|
952
|
-
appId:
|
|
952
|
+
appId: undefined // appId is optional and should be undefined when not resolved
|
|
953
953
|
}),
|
|
954
954
|
'read:page.dashboard',
|
|
955
955
|
'dashboard',
|
package/src/rbac/config.ts
CHANGED
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
|
|
10
10
|
import { SupabaseClient } from '@supabase/supabase-js';
|
|
11
11
|
import { Database } from '../types/database';
|
|
12
|
+
import { RBACSecurityConfig } from './security';
|
|
12
13
|
|
|
13
14
|
export type LogLevel = 'error' | 'warn' | 'info' | 'debug';
|
|
14
15
|
|
|
@@ -26,6 +27,7 @@ export interface RBACConfig {
|
|
|
26
27
|
enabled?: boolean;
|
|
27
28
|
logLevel?: LogLevel;
|
|
28
29
|
};
|
|
30
|
+
security?: Partial<RBACSecurityConfig>;
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export interface RBACLogger {
|
package/src/rbac/engine.ts
CHANGED
|
@@ -36,7 +36,8 @@ import {
|
|
|
36
36
|
RBACSecurityValidator,
|
|
37
37
|
RBACSecurityMiddleware,
|
|
38
38
|
SecurityContext,
|
|
39
|
-
DEFAULT_SECURITY_CONFIG
|
|
39
|
+
DEFAULT_SECURITY_CONFIG,
|
|
40
|
+
RBACSecurityConfig
|
|
40
41
|
} from './security';
|
|
41
42
|
|
|
42
43
|
/**
|
|
@@ -49,9 +50,14 @@ export class RBACEngine {
|
|
|
49
50
|
private supabase: SupabaseClient<Database>;
|
|
50
51
|
private securityMiddleware: RBACSecurityMiddleware;
|
|
51
52
|
|
|
52
|
-
constructor(supabase: SupabaseClient<Database>) {
|
|
53
|
+
constructor(supabase: SupabaseClient<Database>, securityConfig?: Partial<RBACSecurityConfig>) {
|
|
53
54
|
this.supabase = supabase;
|
|
54
|
-
|
|
55
|
+
// Merge provided security config with defaults
|
|
56
|
+
const mergedSecurityConfig: RBACSecurityConfig = {
|
|
57
|
+
...DEFAULT_SECURITY_CONFIG,
|
|
58
|
+
...securityConfig,
|
|
59
|
+
};
|
|
60
|
+
this.securityMiddleware = new RBACSecurityMiddleware(mergedSecurityConfig);
|
|
55
61
|
|
|
56
62
|
// Initialize cache invalidation for automatic cache clearing
|
|
57
63
|
initializeCacheInvalidation(supabase);
|
|
@@ -589,9 +595,13 @@ export class RBACEngine {
|
|
|
589
595
|
* Create an RBAC engine instance
|
|
590
596
|
*
|
|
591
597
|
* @param supabase - Supabase client
|
|
598
|
+
* @param securityConfig - Optional security configuration
|
|
592
599
|
* @returns RBACEngine instance
|
|
593
600
|
*/
|
|
594
|
-
export function createRBACEngine(
|
|
595
|
-
|
|
601
|
+
export function createRBACEngine(
|
|
602
|
+
supabase: SupabaseClient<Database>,
|
|
603
|
+
securityConfig?: Partial<RBACSecurityConfig>
|
|
604
|
+
): RBACEngine {
|
|
605
|
+
return new RBACEngine(supabase, securityConfig);
|
|
596
606
|
}
|
|
597
607
|
|
package/src/rbac/security.ts
CHANGED
|
@@ -251,7 +251,7 @@ export const DEFAULT_SECURITY_CONFIG: RBACSecurityConfig = {
|
|
|
251
251
|
enableInputValidation: true,
|
|
252
252
|
enableRateLimiting: true,
|
|
253
253
|
enableAuditLogging: true,
|
|
254
|
-
maxPermissionChecksPerMinute: 100
|
|
254
|
+
maxPermissionChecksPerMinute: 1000, // Increased from 100 to 1000 for normal app usage
|
|
255
255
|
suspiciousActivityThreshold: 10,
|
|
256
256
|
};
|
|
257
257
|
|