@jmruthers/pace-core 0.5.111 → 0.5.112
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/dist/{DataTable-5W2HVLLV.js → DataTable-3D3BUZDV.js} +8 -8
- package/dist/{UnifiedAuthProvider-LUM3QLS5.js → UnifiedAuthProvider-KZZUO27W.js} +3 -3
- package/dist/{api-SIZPFBFX.js → api-QPMBZZUZ.js} +3 -3
- package/dist/{audit-5JI5T3SL.js → audit-H4YJJF7R.js} +2 -2
- package/dist/{chunk-IWJYNWXN.js → chunk-3OGQLOJM.js} +11 -3
- package/dist/chunk-3OGQLOJM.js.map +1 -0
- package/dist/{chunk-TDFBX7KJ.js → chunk-7H75SHXZ.js} +2 -2
- package/dist/{chunk-EFVQBYFN.js → chunk-BUN7NMV7.js} +2 -2
- package/dist/{chunk-ACYQNYHB.js → chunk-C5RN4TE5.js} +7 -7
- package/dist/{chunk-2BIDKXQU.js → chunk-EKVVTPIF.js} +82 -23
- package/dist/chunk-EKVVTPIF.js.map +1 -0
- package/dist/{chunk-X7SPKHYZ.js → chunk-F6QB26OS.js} +4 -4
- package/dist/{chunk-UGVU7L7N.js → chunk-I7JC7PTJ.js} +6 -6
- package/dist/chunk-I7JC7PTJ.js.map +1 -0
- package/dist/{chunk-I5YM5BGS.js → chunk-L36JW4KV.js} +2 -2
- package/dist/{chunk-ZL45MG76.js → chunk-MNSGWRPB.js} +15 -15
- package/dist/{chunk-JE2GFA3O.js → chunk-NEONKMTU.js} +3 -3
- package/dist/{chunk-MW73E7SP.js → chunk-OO3V7W4H.js} +2 -2
- package/dist/chunk-OO3V7W4H.js.map +1 -0
- package/dist/{chunk-PXXS26G5.js → chunk-TAJRS6YB.js} +2 -2
- package/dist/{chunk-TD4BXGPE.js → chunk-WMPZY26G.js} +8 -4
- package/dist/{chunk-TD4BXGPE.js.map → chunk-WMPZY26G.js.map} +1 -1
- package/dist/components.js +10 -10
- package/dist/hooks.js +7 -7
- package/dist/index.js +13 -13
- package/dist/providers.js +2 -2
- package/dist/rbac/index.js +9 -9
- 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 +8 -8
- package/docs/api/classes/RBACCache.md +1 -1
- package/docs/api/classes/RBACEngine.md +1 -1
- 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 +1 -1
- package/docs/api/interfaces/RBACLogger.md +1 -1
- 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 +12 -12
- package/package.json +1 -1
- package/src/components/DataTable/DataTable.test.tsx +405 -154
- package/src/components/DataTable/components/DataTableCore.tsx +6 -1
- package/src/components/EventSelector/EventSelector.tsx +32 -2
- package/src/components/NavigationMenu/NavigationMenu.test.tsx +56 -8
- package/src/components/NavigationMenu/NavigationMenu.tsx +75 -12
- package/src/rbac/audit-enhanced.ts +14 -2
- package/src/rbac/audit.test.ts +16 -6
- package/src/rbac/audit.ts +11 -1
- package/src/rbac/hooks/usePermissions.ts +18 -2
- package/src/services/EventService.ts +3 -2
- package/dist/chunk-2BIDKXQU.js.map +0 -1
- package/dist/chunk-IWJYNWXN.js.map +0 -1
- package/dist/chunk-MW73E7SP.js.map +0 -1
- package/dist/chunk-UGVU7L7N.js.map +0 -1
- /package/dist/{DataTable-5W2HVLLV.js.map → DataTable-3D3BUZDV.js.map} +0 -0
- /package/dist/{UnifiedAuthProvider-LUM3QLS5.js.map → UnifiedAuthProvider-KZZUO27W.js.map} +0 -0
- /package/dist/{api-SIZPFBFX.js.map → api-QPMBZZUZ.js.map} +0 -0
- /package/dist/{audit-5JI5T3SL.js.map → audit-H4YJJF7R.js.map} +0 -0
- /package/dist/{chunk-TDFBX7KJ.js.map → chunk-7H75SHXZ.js.map} +0 -0
- /package/dist/{chunk-EFVQBYFN.js.map → chunk-BUN7NMV7.js.map} +0 -0
- /package/dist/{chunk-ACYQNYHB.js.map → chunk-C5RN4TE5.js.map} +0 -0
- /package/dist/{chunk-X7SPKHYZ.js.map → chunk-F6QB26OS.js.map} +0 -0
- /package/dist/{chunk-I5YM5BGS.js.map → chunk-L36JW4KV.js.map} +0 -0
- /package/dist/{chunk-ZL45MG76.js.map → chunk-MNSGWRPB.js.map} +0 -0
- /package/dist/{chunk-JE2GFA3O.js.map → chunk-NEONKMTU.js.map} +0 -0
- /package/dist/{chunk-PXXS26G5.js.map → chunk-TAJRS6YB.js.map} +0 -0
|
@@ -54,10 +54,10 @@ import {
|
|
|
54
54
|
sortHierarchicalDataWithSorting,
|
|
55
55
|
validateHierarchicalData,
|
|
56
56
|
validatePaginationConfig
|
|
57
|
-
} from "./chunk-
|
|
58
|
-
import "./chunk-
|
|
59
|
-
import "./chunk-
|
|
60
|
-
import "./chunk-
|
|
57
|
+
} from "./chunk-WMPZY26G.js";
|
|
58
|
+
import "./chunk-I7JC7PTJ.js";
|
|
59
|
+
import "./chunk-TAJRS6YB.js";
|
|
60
|
+
import "./chunk-3OGQLOJM.js";
|
|
61
61
|
import {
|
|
62
62
|
CircuitBreaker,
|
|
63
63
|
DEFAULT_FALLBACK_CONFIG,
|
|
@@ -76,9 +76,9 @@ import {
|
|
|
76
76
|
throttle,
|
|
77
77
|
useDataTablePerformance
|
|
78
78
|
} from "./chunk-4OX5PXHX.js";
|
|
79
|
-
import "./chunk-
|
|
80
|
-
import "./chunk-
|
|
81
|
-
import "./chunk-
|
|
79
|
+
import "./chunk-L36JW4KV.js";
|
|
80
|
+
import "./chunk-7H75SHXZ.js";
|
|
81
|
+
import "./chunk-OO3V7W4H.js";
|
|
82
82
|
import "./chunk-PYUXFQJ3.js";
|
|
83
83
|
import "./chunk-JCQZ6LA7.js";
|
|
84
84
|
import "./chunk-BDZUMRBD.js";
|
|
@@ -157,4 +157,4 @@ export {
|
|
|
157
157
|
validateHierarchicalData,
|
|
158
158
|
validatePaginationConfig
|
|
159
159
|
};
|
|
160
|
-
//# sourceMappingURL=DataTable-
|
|
160
|
+
//# sourceMappingURL=DataTable-3D3BUZDV.js.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import {
|
|
2
2
|
init_UnifiedAuthProvider
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-7H75SHXZ.js";
|
|
4
4
|
import {
|
|
5
5
|
UnifiedAuthProvider,
|
|
6
6
|
useUnifiedAuth
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OO3V7W4H.js";
|
|
8
8
|
import "./chunk-BDZUMRBD.js";
|
|
9
9
|
import "./chunk-SMJZMKYN.js";
|
|
10
10
|
import "./chunk-PLDDJCW6.js";
|
|
@@ -13,4 +13,4 @@ export {
|
|
|
13
13
|
UnifiedAuthProvider,
|
|
14
14
|
useUnifiedAuth
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=UnifiedAuthProvider-
|
|
16
|
+
//# sourceMappingURL=UnifiedAuthProvider-KZZUO27W.js.map
|
|
@@ -20,8 +20,8 @@ import {
|
|
|
20
20
|
isSuperAdmin,
|
|
21
21
|
resolveAppContext,
|
|
22
22
|
setupRBAC
|
|
23
|
-
} from "./chunk-
|
|
24
|
-
import "./chunk-
|
|
23
|
+
} from "./chunk-TAJRS6YB.js";
|
|
24
|
+
import "./chunk-3OGQLOJM.js";
|
|
25
25
|
import "./chunk-PLDDJCW6.js";
|
|
26
26
|
export {
|
|
27
27
|
OrganisationContextRequiredError,
|
|
@@ -46,4 +46,4 @@ export {
|
|
|
46
46
|
resolveAppContext,
|
|
47
47
|
setupRBAC
|
|
48
48
|
};
|
|
49
|
-
//# sourceMappingURL=api-
|
|
49
|
+
//# sourceMappingURL=api-QPMBZZUZ.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
emitAuditEvent,
|
|
5
5
|
getGlobalAuditManager,
|
|
6
6
|
setGlobalAuditManager
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-3OGQLOJM.js";
|
|
8
8
|
import "./chunk-PLDDJCW6.js";
|
|
9
9
|
export {
|
|
10
10
|
RBACAuditManager,
|
|
@@ -13,4 +13,4 @@ export {
|
|
|
13
13
|
getGlobalAuditManager,
|
|
14
14
|
setGlobalAuditManager
|
|
15
15
|
};
|
|
16
|
-
//# sourceMappingURL=audit-
|
|
16
|
+
//# sourceMappingURL=audit-H4YJJF7R.js.map
|
|
@@ -52,6 +52,11 @@ var RBACAuditManager = class {
|
|
|
52
52
|
note: "Organisation context is required for RBAC operations. This may indicate a security issue or missing context derivation."
|
|
53
53
|
});
|
|
54
54
|
}
|
|
55
|
+
const rawPageId = "pageId" in event ? event.pageId : void 0;
|
|
56
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
57
|
+
const isValidPageIdUuid = rawPageId && uuidRegex.test(rawPageId);
|
|
58
|
+
const pageIdUuid = isValidPageIdUuid ? rawPageId : void 0;
|
|
59
|
+
const pageIdName = rawPageId && !isValidPageIdUuid ? rawPageId : void 0;
|
|
55
60
|
const auditEvent = {
|
|
56
61
|
event_type: event.type,
|
|
57
62
|
user_id: event.userId,
|
|
@@ -61,7 +66,8 @@ var RBACAuditManager = class {
|
|
|
61
66
|
// Explicitly null if missing
|
|
62
67
|
event_id: "eventId" in event ? event.eventId : void 0,
|
|
63
68
|
app_id: "appId" in event ? event.appId : void 0,
|
|
64
|
-
page_id:
|
|
69
|
+
page_id: pageIdUuid,
|
|
70
|
+
// Only set if it's a valid UUID
|
|
65
71
|
permission: "permission" in event ? event.permission : void 0,
|
|
66
72
|
decision: "decision" in event ? event.decision : void 0,
|
|
67
73
|
source: "source" in event ? event.source : "api",
|
|
@@ -73,7 +79,9 @@ var RBACAuditManager = class {
|
|
|
73
79
|
cache_hit: "cache_hit" in event ? event.cache_hit : void 0,
|
|
74
80
|
cache_source: "cache_source" in event ? event.cache_source : void 0,
|
|
75
81
|
// Explicit flag indicating this event had no organisation context
|
|
76
|
-
no_organisation_context: !event.organisationId
|
|
82
|
+
no_organisation_context: !event.organisationId,
|
|
83
|
+
// Store page name/identifier in metadata if it's not a UUID
|
|
84
|
+
page_name: pageIdName
|
|
77
85
|
}
|
|
78
86
|
};
|
|
79
87
|
const { error } = await this.supabase.from("rbac_audit_events").insert([auditEvent]);
|
|
@@ -197,4 +205,4 @@ export {
|
|
|
197
205
|
getGlobalAuditManager,
|
|
198
206
|
emitAuditEvent
|
|
199
207
|
};
|
|
200
|
-
//# sourceMappingURL=chunk-
|
|
208
|
+
//# sourceMappingURL=chunk-3OGQLOJM.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/rbac/audit.ts"],"sourcesContent":["/**\n * RBAC Audit Events System\n * @package @jmruthers/pace-core\n * @module RBAC/Audit\n * @since 1.0.0\n * \n * This module provides structured audit event emission for all RBAC operations.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport { \n UUID, \n AuditEventSource, \n RBACAuditEvent \n} from './types';\n\n/**\n * Audit event payload for permission checks\n */\nexport interface PermissionCheckAuditEvent {\n type: 'permission_check';\n userId: UUID;\n organisationId: UUID;\n eventId?: string;\n appId?: UUID;\n pageId?: UUID;\n permission: string;\n decision: boolean;\n source: AuditEventSource;\n bypass?: boolean;\n duration_ms: number;\n cache_hit?: boolean;\n cache_source?: 'memory' | 'database' | 'rpc';\n metadata?: Record<string, any>;\n}\n\n/**\n * Audit event payload for permission denied\n */\nexport interface PermissionDeniedAuditEvent {\n type: 'permission_denied';\n userId: UUID;\n organisationId: UUID;\n eventId?: string;\n appId?: UUID;\n pageId?: UUID;\n permission: string;\n source: AuditEventSource;\n metadata?: Record<string, any>;\n}\n\n/**\n * Audit event payload for role granted\n */\nexport interface RoleGrantedAuditEvent {\n type: 'role_granted';\n userId: UUID;\n organisationId: UUID;\n eventId?: string;\n appId?: UUID;\n role: string;\n grantedBy: UUID;\n metadata?: Record<string, any>;\n}\n\n/**\n * Audit event payload for role revoked\n */\nexport interface RoleRevokedAuditEvent {\n type: 'role_denied';\n userId: UUID;\n organisationId: UUID;\n eventId?: string;\n appId?: UUID;\n role: string;\n revokedBy: UUID;\n metadata?: Record<string, any>;\n}\n\n/**\n * Audit event payload for RLS denied\n */\nexport interface RLSDeniedAuditEvent {\n type: 'rls_denied';\n userId: UUID;\n organisationId: UUID;\n table: string;\n operation: string;\n metadata?: Record<string, any>;\n}\n\n/**\n * Union type for all audit events\n */\nexport type AuditEventPayload = \n | PermissionCheckAuditEvent\n | PermissionDeniedAuditEvent\n | RoleGrantedAuditEvent\n | RoleRevokedAuditEvent\n | RLSDeniedAuditEvent;\n\n/**\n * RBAC Audit Manager\n * \n * Handles emission of structured audit events for all RBAC operations.\n */\nexport class RBACAuditManager {\n private supabase: SupabaseClient<Database>;\n private enabled: boolean = true;\n\n constructor(supabase: SupabaseClient<Database>) {\n this.supabase = supabase;\n }\n\n /**\n * Enable or disable audit logging\n * \n * @param enabled - Whether to enable audit logging\n */\n setEnabled(enabled: boolean): void {\n this.enabled = enabled;\n }\n\n /**\n * Check if audit logging is enabled\n * \n * @returns True if audit logging is enabled\n */\n isEnabled(): boolean {\n return this.enabled;\n }\n\n /**\n * Emit an audit event\n * \n * @param event - Audit event payload\n * @returns Promise that resolves when event is logged\n */\n async emitEvent(event: AuditEventPayload): Promise<void> {\n if (!this.enabled) {\n return;\n }\n\n // Validate required fields before attempting to insert\n // MANDATORY: All audit events must have userId\n if (!event.userId) {\n console.error('[RBAC Audit] CRITICAL: Cannot log audit event without userId:', {\n eventType: event.type,\n organisationId: event.organisationId\n });\n return;\n }\n\n // WARNING: Some audit events may not have organisationId (e.g., global admin operations)\n // Log these for security monitoring even if organisationId is missing\n if (!event.organisationId) {\n console.warn('[RBAC Audit] Audit event without organisation context:', {\n userId: event.userId,\n eventType: event.type,\n note: 'This should be investigated for security compliance'\n });\n }\n\n try {\n // Since organisationId is now required in SecurityContext, this should rarely happen\n // But we still handle the edge case properly without masking it\n if (!event.organisationId) {\n console.warn('[RBAC Audit] Audit event without organisation context - this should be investigated:', {\n userId: event.userId,\n eventType: event.type,\n note: 'Organisation context is required for RBAC operations. This may indicate a security issue or missing context derivation.'\n });\n }\n\n // Validate pageId: only include in page_id column if it's a valid UUID\n // Otherwise, store it in metadata to avoid database errors\n const rawPageId = 'pageId' in event ? event.pageId : undefined;\n const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;\n const isValidPageIdUuid = rawPageId && uuidRegex.test(rawPageId);\n const pageIdUuid: UUID | undefined = isValidPageIdUuid ? (rawPageId as UUID) : undefined;\n const pageIdName: string | undefined = rawPageId && !isValidPageIdUuid ? rawPageId : undefined;\n\n const auditEvent: Omit<RBACAuditEvent, 'id' | 'created_at'> = {\n event_type: event.type,\n user_id: event.userId,\n // Store organisationId - nullable to properly track missing context cases\n // Do NOT use fallback UUID as it masks security issues\n organisation_id: event.organisationId || null, // Explicitly null if missing\n event_id: 'eventId' in event ? event.eventId : undefined,\n app_id: 'appId' in event ? event.appId : undefined,\n page_id: pageIdUuid, // Only set if it's a valid UUID\n permission: 'permission' in event ? event.permission : undefined,\n decision: 'decision' in event ? event.decision : undefined,\n source: 'source' in event ? event.source : 'api', // Default to 'api' if not provided\n bypass: 'bypass' in event ? event.bypass : undefined,\n duration_ms: 'duration_ms' in event ? event.duration_ms : undefined,\n metadata: {\n ...event.metadata,\n cache_hit: 'cache_hit' in event ? event.cache_hit : undefined,\n cache_source: 'cache_source' in event ? event.cache_source : undefined,\n // Explicit flag indicating this event had no organisation context\n no_organisation_context: !event.organisationId,\n // Store page name/identifier in metadata if it's not a UUID\n page_name: pageIdName,\n },\n };\n\n const { error } = await (this.supabase as any)\n .from('rbac_audit_events')\n .insert([auditEvent]);\n\n if (error) {\n // Log the error for debugging but don't throw\n console.warn('[RBAC Audit] Failed to insert audit event:', {\n error: error.message,\n code: error.code,\n details: error.details,\n hint: error.hint,\n event: auditEvent\n });\n }\n } catch (error) {\n // Log unexpected errors but don't throw\n console.error('[RBAC Audit] Unexpected error during audit logging:', error);\n }\n }\n\n /**\n * Emit a permission check audit event\n * \n * @param event - Permission check event data\n */\n async emitPermissionCheck(event: Omit<PermissionCheckAuditEvent, 'type'>): Promise<void> {\n await this.emitEvent({\n type: 'permission_check',\n ...event,\n });\n }\n\n /**\n * Emit a permission denied audit event\n * \n * @param event - Permission denied event data\n */\n async emitPermissionDenied(event: Omit<PermissionDeniedAuditEvent, 'type'>): Promise<void> {\n await this.emitEvent({\n type: 'permission_denied',\n ...event,\n });\n }\n\n /**\n * Emit a role granted audit event\n * \n * @param event - Role granted event data\n */\n async emitRoleGranted(event: Omit<RoleGrantedAuditEvent, 'type'>): Promise<void> {\n await this.emitEvent({\n type: 'role_granted',\n ...event,\n });\n }\n\n /**\n * Emit a role revoked audit event\n * \n * @param event - Role revoked event data\n */\n async emitRoleRevoked(event: Omit<RoleRevokedAuditEvent, 'type'>): Promise<void> {\n await this.emitEvent({\n type: 'role_denied',\n ...event,\n });\n }\n\n /**\n * Emit an RLS denied audit event\n * \n * @param event - RLS denied event data\n */\n async emitRLSDenied(event: Omit<RLSDeniedAuditEvent, 'type'>): Promise<void> {\n await this.emitEvent({\n type: 'rls_denied',\n ...event,\n });\n }\n\n /**\n * Get audit events for a user\n * \n * @param userId - User ID\n * @param limit - Maximum number of events to return\n * @returns Promise resolving to audit events\n */\n async getUserAuditEvents(userId: UUID, limit: number = 100): Promise<RBACAuditEvent[]> {\n const { data, error } = await this.supabase\n .from('rbac_audit_events')\n .select('*')\n .eq('user_id', userId)\n .order('created_at', { ascending: false })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get audit events: ${error.message}`);\n }\n\n return data || [];\n }\n\n /**\n * Get audit events for an organisation\n * \n * @param organisationId - Organisation ID\n * @param limit - Maximum number of events to return\n * @returns Promise resolving to audit events\n */\n async getOrganisationAuditEvents(organisationId: UUID, limit: number = 100): Promise<RBACAuditEvent[]> {\n const { data, error } = await this.supabase\n .from('rbac_audit_events')\n .select('*')\n .eq('organisation_id', organisationId)\n .order('created_at', { ascending: false })\n .limit(limit);\n\n if (error) {\n throw new Error(`Failed to get audit events: ${error.message}`);\n }\n\n return data || [];\n }\n}\n\n/**\n * Create an audit manager instance\n * \n * @param supabase - Supabase client\n * @returns RBACAuditManager instance\n */\nexport function createAuditManager(supabase: SupabaseClient<Database>): RBACAuditManager {\n return new RBACAuditManager(supabase);\n}\n\n/**\n * Global audit manager instance\n * \n * This is set by the RBAC engine when it initializes.\n */\nlet globalAuditManager: RBACAuditManager | null = null;\n\n/**\n * Set the global audit manager\n * \n * @param manager - Audit manager instance\n */\nexport function setGlobalAuditManager(manager: RBACAuditManager): void {\n globalAuditManager = manager;\n}\n\n/**\n * Get the global audit manager\n * \n * @returns Global audit manager or null if not set\n */\nexport function getGlobalAuditManager(): RBACAuditManager | null {\n return globalAuditManager;\n}\n\n/**\n * Emit an audit event using the global audit manager\n * \n * @param event - Audit event payload\n */\nexport async function emitAuditEvent(event: AuditEventPayload): Promise<void> {\n if (globalAuditManager) {\n await globalAuditManager.emitEvent(event);\n }\n}\n"],"mappings":"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","names":[]}
|
|
@@ -2,7 +2,7 @@ import {
|
|
|
2
2
|
UnifiedAuthProvider,
|
|
3
3
|
init_UnifiedAuthProvider,
|
|
4
4
|
useUnifiedAuth
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-OO3V7W4H.js";
|
|
6
6
|
import {
|
|
7
7
|
__esm,
|
|
8
8
|
__export
|
|
@@ -24,4 +24,4 @@ export {
|
|
|
24
24
|
UnifiedAuthProvider_exports,
|
|
25
25
|
init_UnifiedAuthProvider2 as init_UnifiedAuthProvider
|
|
26
26
|
};
|
|
27
|
-
//# sourceMappingURL=chunk-
|
|
27
|
+
//# sourceMappingURL=chunk-7H75SHXZ.js.map
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
init_InactivityServiceProvider,
|
|
5
5
|
init_OrganisationServiceProvider,
|
|
6
6
|
init_UnifiedAuthProvider
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-OO3V7W4H.js";
|
|
8
8
|
|
|
9
9
|
// src/providers/index.ts
|
|
10
10
|
init_UnifiedAuthProvider();
|
|
@@ -12,4 +12,4 @@ init_EventServiceProvider();
|
|
|
12
12
|
init_OrganisationServiceProvider();
|
|
13
13
|
init_InactivityServiceProvider();
|
|
14
14
|
init_AuthServiceProvider();
|
|
15
|
-
//# sourceMappingURL=chunk-
|
|
15
|
+
//# sourceMappingURL=chunk-BUN7NMV7.js.map
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import {
|
|
2
2
|
init_OrganisationProvider,
|
|
3
3
|
usePublicPageContext
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-F6QB26OS.js";
|
|
5
5
|
import {
|
|
6
6
|
init_useOrganisations,
|
|
7
7
|
useEvents,
|
|
8
8
|
useOrganisations
|
|
9
|
-
} from "./chunk-
|
|
9
|
+
} from "./chunk-L36JW4KV.js";
|
|
10
10
|
import {
|
|
11
11
|
useUnifiedAuth
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-OO3V7W4H.js";
|
|
13
13
|
import {
|
|
14
14
|
applyPalette,
|
|
15
15
|
clearPalette,
|
|
@@ -96,7 +96,7 @@ var useOrganisationSecurity = () => {
|
|
|
96
96
|
const targetOrgId = orgId || selectedOrganisation?.id;
|
|
97
97
|
if (!targetOrgId || !user) return false;
|
|
98
98
|
try {
|
|
99
|
-
const { isPermitted } = await import("./api-
|
|
99
|
+
const { isPermitted } = await import("./api-QPMBZZUZ.js");
|
|
100
100
|
const scope = {
|
|
101
101
|
organisationId: targetOrgId,
|
|
102
102
|
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
@@ -119,7 +119,7 @@ var useOrganisationSecurity = () => {
|
|
|
119
119
|
const targetOrgId = orgId || selectedOrganisation?.id;
|
|
120
120
|
if (!targetOrgId || !user) return [];
|
|
121
121
|
try {
|
|
122
|
-
const { getPermissionMap } = await import("./api-
|
|
122
|
+
const { getPermissionMap } = await import("./api-QPMBZZUZ.js");
|
|
123
123
|
const scope = {
|
|
124
124
|
organisationId: targetOrgId,
|
|
125
125
|
eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
|
|
@@ -140,7 +140,7 @@ var useOrganisationSecurity = () => {
|
|
|
140
140
|
if (!user || !selectedOrganisation) return;
|
|
141
141
|
try {
|
|
142
142
|
if (selectedOrganisation.id) {
|
|
143
|
-
const { emitAuditEvent } = await import("./audit-
|
|
143
|
+
const { emitAuditEvent } = await import("./audit-H4YJJF7R.js");
|
|
144
144
|
await emitAuditEvent({
|
|
145
145
|
type: "permission_check",
|
|
146
146
|
userId: user.id,
|
|
@@ -706,4 +706,4 @@ export {
|
|
|
706
706
|
generatePublicRoutePath,
|
|
707
707
|
extractEventCodeFromPath
|
|
708
708
|
};
|
|
709
|
-
//# sourceMappingURL=chunk-
|
|
709
|
+
//# sourceMappingURL=chunk-C5RN4TE5.js.map
|
|
@@ -25,16 +25,16 @@ import {
|
|
|
25
25
|
SelectSeparator,
|
|
26
26
|
SelectTrigger,
|
|
27
27
|
SelectValue
|
|
28
|
-
} from "./chunk-
|
|
28
|
+
} from "./chunk-WMPZY26G.js";
|
|
29
29
|
import {
|
|
30
30
|
useCan,
|
|
31
31
|
usePermissions,
|
|
32
32
|
useRBAC,
|
|
33
33
|
useResolvedScope
|
|
34
|
-
} from "./chunk-
|
|
34
|
+
} from "./chunk-I7JC7PTJ.js";
|
|
35
35
|
import {
|
|
36
36
|
isSuperAdmin
|
|
37
|
-
} from "./chunk-
|
|
37
|
+
} from "./chunk-TAJRS6YB.js";
|
|
38
38
|
import {
|
|
39
39
|
OrganisationProvider_exports,
|
|
40
40
|
PublicErrorBoundary,
|
|
@@ -49,7 +49,7 @@ import {
|
|
|
49
49
|
useIsPublicPage,
|
|
50
50
|
usePublicFileDisplay,
|
|
51
51
|
usePublicPageContext
|
|
52
|
-
} from "./chunk-
|
|
52
|
+
} from "./chunk-F6QB26OS.js";
|
|
53
53
|
import {
|
|
54
54
|
useToast
|
|
55
55
|
} from "./chunk-4OX5PXHX.js";
|
|
@@ -57,11 +57,11 @@ import {
|
|
|
57
57
|
init_useOrganisations,
|
|
58
58
|
useEvents,
|
|
59
59
|
useOrganisations
|
|
60
|
-
} from "./chunk-
|
|
60
|
+
} from "./chunk-L36JW4KV.js";
|
|
61
61
|
import {
|
|
62
62
|
UnifiedAuthProvider_exports,
|
|
63
63
|
init_UnifiedAuthProvider as init_UnifiedAuthProvider2
|
|
64
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-7H75SHXZ.js";
|
|
65
65
|
import {
|
|
66
66
|
EventServiceContext,
|
|
67
67
|
EventServiceProvider,
|
|
@@ -71,7 +71,7 @@ import {
|
|
|
71
71
|
useEventService,
|
|
72
72
|
useSessionRestoration,
|
|
73
73
|
useUnifiedAuth
|
|
74
|
-
} from "./chunk-
|
|
74
|
+
} from "./chunk-OO3V7W4H.js";
|
|
75
75
|
import {
|
|
76
76
|
LoadingSpinner
|
|
77
77
|
} from "./chunk-CDQ3PX7L.js";
|
|
@@ -585,7 +585,23 @@ function EventSelector({
|
|
|
585
585
|
return [...events].sort((a, b) => getTime(b) - getTime(a));
|
|
586
586
|
}, [events]);
|
|
587
587
|
useEffect(() => {
|
|
588
|
-
if (!selectedEvent && events.length > 0) {
|
|
588
|
+
if (!selectedEvent && events.length > 0 && !isLoading) {
|
|
589
|
+
const persistedEventId = localStorage.getItem("pace-core-selected-event") || sessionStorage.getItem("pace-core-selected-event");
|
|
590
|
+
if (persistedEventId) {
|
|
591
|
+
const persistedEvent = events.find((e) => e.event_id === persistedEventId);
|
|
592
|
+
if (persistedEvent) {
|
|
593
|
+
console.debug("[EventSelector] Persisted event found in storage but not selected:", persistedEventId);
|
|
594
|
+
return;
|
|
595
|
+
} else {
|
|
596
|
+
localStorage.removeItem("pace-core-selected-event");
|
|
597
|
+
sessionStorage.removeItem("pace-core-selected-event");
|
|
598
|
+
autoSelectEvent();
|
|
599
|
+
}
|
|
600
|
+
} else {
|
|
601
|
+
autoSelectEvent();
|
|
602
|
+
}
|
|
603
|
+
}
|
|
604
|
+
function autoSelectEvent() {
|
|
589
605
|
const today = /* @__PURE__ */ new Date();
|
|
590
606
|
const startOfToday = new Date(today.getFullYear(), today.getMonth(), today.getDate()).getTime();
|
|
591
607
|
const next = [...events].filter((e) => e.event_date && new Date(e.event_date).getTime() >= startOfToday).sort((a, b) => new Date(a.event_date).getTime() - new Date(b.event_date).getTime())[0];
|
|
@@ -605,7 +621,7 @@ function EventSelector({
|
|
|
605
621
|
}
|
|
606
622
|
}
|
|
607
623
|
}
|
|
608
|
-
}, [events, selectedEvent, setSelectedEvent, onEventChange]);
|
|
624
|
+
}, [events, selectedEvent, setSelectedEvent, onEventChange, isLoading]);
|
|
609
625
|
if (isLoading) {
|
|
610
626
|
return /* @__PURE__ */ jsxs4("div", { className: `flex items-center gap-2 ${className}`, children: [
|
|
611
627
|
/* @__PURE__ */ jsx8(LoadingSpinner, { size: "sm" }),
|
|
@@ -920,14 +936,50 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
920
936
|
selectedOrganisationId: selectedOrganisation?.id || null,
|
|
921
937
|
selectedEventId: selectedEvent?.event_id || null
|
|
922
938
|
});
|
|
939
|
+
const stableScopeRef = React9.useRef({
|
|
940
|
+
organisationId: "",
|
|
941
|
+
eventId: void 0,
|
|
942
|
+
appId: void 0
|
|
943
|
+
});
|
|
944
|
+
if (resolvedScope?.organisationId) {
|
|
945
|
+
const newOrgId = resolvedScope.organisationId;
|
|
946
|
+
const newEventId = resolvedScope.eventId;
|
|
947
|
+
const newAppId = resolvedScope.appId;
|
|
948
|
+
if (stableScopeRef.current.organisationId !== newOrgId || stableScopeRef.current.eventId !== newEventId || stableScopeRef.current.appId !== newAppId) {
|
|
949
|
+
stableScopeRef.current = {
|
|
950
|
+
organisationId: newOrgId,
|
|
951
|
+
eventId: newEventId,
|
|
952
|
+
appId: newAppId
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
} else if (!resolvedScope) {
|
|
956
|
+
if (stableScopeRef.current.organisationId !== "") {
|
|
957
|
+
stableScopeRef.current = {
|
|
958
|
+
organisationId: "",
|
|
959
|
+
eventId: void 0,
|
|
960
|
+
appId: void 0
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
}
|
|
964
|
+
const stableScope = stableScopeRef.current;
|
|
923
965
|
const userId = authContext?.user?.id || "";
|
|
924
|
-
const
|
|
925
|
-
const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading } = usePermissions(
|
|
966
|
+
const { permissions: permissionMap, hasAnyPermission, isLoading: permissionsLoading, error: permissionsError } = usePermissions(
|
|
926
967
|
userId,
|
|
927
|
-
|
|
968
|
+
stableScope
|
|
928
969
|
);
|
|
929
970
|
const filteredItems = React9.useMemo(() => {
|
|
930
|
-
if (
|
|
971
|
+
if (filterByPermissions) {
|
|
972
|
+
if (!authContext || !rbacContext || scopeLoading || permissionsLoading || !resolvedScope?.organisationId) {
|
|
973
|
+
return [];
|
|
974
|
+
}
|
|
975
|
+
if (permissionsError || !permissionMap || Object.keys(permissionMap).length === 0) {
|
|
976
|
+
console.warn("[NavigationMenu] Permission map is empty or has error - showing no items for security", {
|
|
977
|
+
permissionsError: permissionsError?.message,
|
|
978
|
+
permissionMapSize: permissionMap ? Object.keys(permissionMap).length : 0
|
|
979
|
+
});
|
|
980
|
+
return [];
|
|
981
|
+
}
|
|
982
|
+
} else {
|
|
931
983
|
return (items || []).filter((item) => !item.meta?.hidden);
|
|
932
984
|
}
|
|
933
985
|
const getPageIdFromHref = (href) => {
|
|
@@ -991,19 +1043,25 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
991
1043
|
}
|
|
992
1044
|
}
|
|
993
1045
|
}
|
|
994
|
-
if (item.href
|
|
1046
|
+
if (item.href) {
|
|
995
1047
|
const pageId = item.pageId || getPageIdFromHref(item.href);
|
|
996
1048
|
if (pageId) {
|
|
997
1049
|
const pagePermission = `read:page.${pageId}`;
|
|
998
|
-
const
|
|
999
|
-
|
|
1050
|
+
const isSuperAdmin2 = permissionMap["*"] === true;
|
|
1051
|
+
const hasPagePermission = permissionMap[pagePermission] === true;
|
|
1052
|
+
const finalHasPermission = isSuperAdmin2 || hasPagePermission;
|
|
1053
|
+
if (!finalHasPermission) {
|
|
1000
1054
|
if (auditLog) {
|
|
1001
1055
|
console.log(`[NavigationMenu] Filtering out navigation item "${item.label}" - no page permission:`, {
|
|
1002
1056
|
itemId: item.id,
|
|
1003
1057
|
href: item.href,
|
|
1004
1058
|
pageId,
|
|
1005
1059
|
permission: pagePermission,
|
|
1006
|
-
hasPermission:
|
|
1060
|
+
hasPermission: finalHasPermission,
|
|
1061
|
+
isSuperAdmin: isSuperAdmin2,
|
|
1062
|
+
permissionMapValue: permissionMap[pagePermission],
|
|
1063
|
+
permissionMapKeys: Object.keys(permissionMap).slice(0, 10)
|
|
1064
|
+
// Show first 10 keys for debugging
|
|
1007
1065
|
});
|
|
1008
1066
|
}
|
|
1009
1067
|
return false;
|
|
@@ -1027,7 +1085,8 @@ var NavigationMenu = React9.forwardRef(({
|
|
|
1027
1085
|
children: filteredChildren
|
|
1028
1086
|
};
|
|
1029
1087
|
};
|
|
1030
|
-
|
|
1088
|
+
const filtered = (items || []).map((item) => filterItem(item)).filter((item) => item !== null);
|
|
1089
|
+
return filtered;
|
|
1031
1090
|
}, [
|
|
1032
1091
|
items,
|
|
1033
1092
|
filterByPermissions,
|
|
@@ -1518,7 +1577,7 @@ function PaceAppLayout({
|
|
|
1518
1577
|
appId: user.user_metadata?.appId || user.app_metadata?.appId
|
|
1519
1578
|
};
|
|
1520
1579
|
try {
|
|
1521
|
-
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-
|
|
1580
|
+
const { isSuperAdmin: isSuperAdmin2 } = await import("./api-QPMBZZUZ.js");
|
|
1522
1581
|
const isSuper = await isSuperAdmin2(user.id);
|
|
1523
1582
|
if (isSuper) {
|
|
1524
1583
|
if (isMounted) {
|
|
@@ -1539,7 +1598,7 @@ function PaceAppLayout({
|
|
|
1539
1598
|
return;
|
|
1540
1599
|
}
|
|
1541
1600
|
try {
|
|
1542
|
-
const { getPermissionMap } = await import("./api-
|
|
1601
|
+
const { getPermissionMap } = await import("./api-QPMBZZUZ.js");
|
|
1543
1602
|
const permissionMap = await getPermissionMap({
|
|
1544
1603
|
userId: user.id,
|
|
1545
1604
|
scope: scope2
|
|
@@ -1598,7 +1657,7 @@ function PaceAppLayout({
|
|
|
1598
1657
|
let hasAccess = true;
|
|
1599
1658
|
if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
|
|
1600
1659
|
try {
|
|
1601
|
-
const { isPermittedCached } = await import("./api-
|
|
1660
|
+
const { isPermittedCached } = await import("./api-QPMBZZUZ.js");
|
|
1602
1661
|
const hasPagePermission = await isPermittedCached({
|
|
1603
1662
|
userId: user?.id || "",
|
|
1604
1663
|
scope,
|
|
@@ -1614,7 +1673,7 @@ function PaceAppLayout({
|
|
|
1614
1673
|
}
|
|
1615
1674
|
}
|
|
1616
1675
|
if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
|
|
1617
|
-
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-
|
|
1676
|
+
const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-KZZUO27W.js");
|
|
1618
1677
|
hasAccess = true;
|
|
1619
1678
|
}
|
|
1620
1679
|
if (!isMounted) return;
|
|
@@ -4450,4 +4509,4 @@ export {
|
|
|
4450
4509
|
PublicPageDiagnostic,
|
|
4451
4510
|
PublicPageContextChecker
|
|
4452
4511
|
};
|
|
4453
|
-
//# sourceMappingURL=chunk-
|
|
4512
|
+
//# sourceMappingURL=chunk-EKVVTPIF.js.map
|