@jmruthers/pace-core 0.5.136 → 0.5.139

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.
Files changed (292) hide show
  1. package/dist/{DataTable-CYOHOX3O.js → DataTable-JXFCA2BJ.js} +10 -9
  2. package/dist/{EventLogo-801uofbR.d.ts → EventLogo-rFL_kRjk.d.ts} +73 -1
  3. package/dist/{UnifiedAuthProvider-5E5TUNMS.js → UnifiedAuthProvider-XIQQ7LVU.js} +4 -5
  4. package/dist/{chunk-YLKIDTUK.js → chunk-22WKWKRX.js} +4 -4
  5. package/dist/{chunk-TVYPTYOY.js → chunk-4C7EXCAR.js} +60 -24
  6. package/dist/chunk-4C7EXCAR.js.map +1 -0
  7. package/dist/{chunk-NOHEVYVX.js → chunk-5JMOHWDI.js} +417 -319
  8. package/dist/chunk-5JMOHWDI.js.map +1 -0
  9. package/dist/{chunk-FHWWBIHA.js → chunk-6DXZ6V5Q.js} +5 -5
  10. package/dist/{chunk-2TWNJ46Y.js → chunk-6LAAY47Q.js} +2 -2
  11. package/dist/{chunk-444EZN6N.js → chunk-7QCC6MCP.js} +88 -1
  12. package/dist/chunk-7QCC6MCP.js.map +1 -0
  13. package/dist/chunk-BJPBT3CU.js +21 -0
  14. package/dist/chunk-BJPBT3CU.js.map +1 -0
  15. package/dist/{chunk-L6PGMCMD.js → chunk-BOOI7GK2.js} +38 -12
  16. package/dist/chunk-BOOI7GK2.js.map +1 -0
  17. package/dist/{chunk-XARJS7CD.js → chunk-INQLMHPF.js} +2 -2
  18. package/dist/chunk-JISYG63F.js +70 -0
  19. package/dist/chunk-JISYG63F.js.map +1 -0
  20. package/dist/{chunk-SL2YQDR6.js → chunk-MA6EPSGZ.js} +2 -2
  21. package/dist/{chunk-5DPZ5EAT.js → chunk-OWAG3GSU.js} +1 -3
  22. package/dist/{chunk-LTV3XIJJ.js → chunk-T6JN6LH6.js} +4 -4
  23. package/dist/{chunk-HJGGOMQ6.js → chunk-TLT2ZR3L.js} +147 -103
  24. package/dist/chunk-TLT2ZR3L.js.map +1 -0
  25. package/dist/{chunk-4MT5BGGL.js → chunk-YCWDTTUK.js} +4 -6
  26. package/dist/{chunk-4MT5BGGL.js.map → chunk-YCWDTTUK.js.map} +1 -1
  27. package/dist/components.d.ts +1 -1
  28. package/dist/components.js +12 -11
  29. package/dist/components.js.map +1 -1
  30. package/dist/hooks.js +8 -9
  31. package/dist/hooks.js.map +1 -1
  32. package/dist/index.d.ts +2 -2
  33. package/dist/index.js +15 -14
  34. package/dist/index.js.map +1 -1
  35. package/dist/providers.js +3 -4
  36. package/dist/rbac/index.js +8 -9
  37. package/dist/schema-DTDZQe2u.d.ts +28 -0
  38. package/dist/types.d.ts +152 -3
  39. package/dist/types.js +51 -16
  40. package/dist/types.js.map +1 -1
  41. package/dist/utils.d.ts +89 -4
  42. package/dist/utils.js +214 -96
  43. package/dist/utils.js.map +1 -1
  44. package/dist/validation.d.ts +1 -343
  45. package/dist/validation.js +3 -100
  46. package/docs/api/classes/ColumnFactory.md +1 -1
  47. package/docs/api/classes/ErrorBoundary.md +1 -1
  48. package/docs/api/classes/InvalidScopeError.md +1 -1
  49. package/docs/api/classes/MissingUserContextError.md +1 -1
  50. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  51. package/docs/api/classes/PermissionDeniedError.md +1 -1
  52. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  53. package/docs/api/classes/RBACAuditManager.md +1 -1
  54. package/docs/api/classes/RBACCache.md +1 -1
  55. package/docs/api/classes/RBACEngine.md +1 -1
  56. package/docs/api/classes/RBACError.md +1 -1
  57. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  58. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  59. package/docs/api/classes/StorageUtils.md +1 -1
  60. package/docs/api/enums/FileCategory.md +1 -1
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/BadgeProps.md +27 -0
  63. package/docs/api/interfaces/ButtonProps.md +1 -1
  64. package/docs/api/interfaces/CardProps.md +1 -1
  65. package/docs/api/interfaces/ColorPalette.md +1 -1
  66. package/docs/api/interfaces/ColorShade.md +1 -1
  67. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  68. package/docs/api/interfaces/DataRecord.md +1 -1
  69. package/docs/api/interfaces/DataTableAction.md +1 -1
  70. package/docs/api/interfaces/DataTableColumn.md +1 -1
  71. package/docs/api/interfaces/DataTableProps.md +1 -1
  72. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  73. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  74. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  75. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  76. package/docs/api/interfaces/EventLogoProps.md +1 -1
  77. package/docs/api/interfaces/ExportColumn.md +1 -1
  78. package/docs/api/interfaces/ExportOptions.md +1 -1
  79. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  80. package/docs/api/interfaces/FileMetadata.md +1 -1
  81. package/docs/api/interfaces/FileReference.md +1 -1
  82. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  83. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  84. package/docs/api/interfaces/FileUploadProps.md +1 -1
  85. package/docs/api/interfaces/FooterProps.md +1 -1
  86. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  87. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  88. package/docs/api/interfaces/InputProps.md +1 -1
  89. package/docs/api/interfaces/LabelProps.md +1 -1
  90. package/docs/api/interfaces/LoginFormProps.md +1 -1
  91. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  92. package/docs/api/interfaces/NavigationContextType.md +1 -1
  93. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  94. package/docs/api/interfaces/NavigationItem.md +1 -1
  95. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  96. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  97. package/docs/api/interfaces/Organisation.md +1 -1
  98. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  99. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  100. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  101. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  102. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  103. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  104. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  105. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  106. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  107. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  108. package/docs/api/interfaces/PaletteData.md +1 -1
  109. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  110. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  111. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  112. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  113. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  114. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  115. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  116. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  117. package/docs/api/interfaces/RBACConfig.md +1 -1
  118. package/docs/api/interfaces/RBACLogger.md +1 -1
  119. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  120. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  121. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  122. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  123. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  124. package/docs/api/interfaces/RouteConfig.md +1 -1
  125. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  126. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  127. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  128. package/docs/api/interfaces/StorageConfig.md +1 -1
  129. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  130. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  131. package/docs/api/interfaces/StorageListOptions.md +1 -1
  132. package/docs/api/interfaces/StorageListResult.md +1 -1
  133. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  134. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  135. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  136. package/docs/api/interfaces/StyleImport.md +1 -1
  137. package/docs/api/interfaces/SwitchProps.md +1 -1
  138. package/docs/api/interfaces/ToastActionElement.md +1 -1
  139. package/docs/api/interfaces/ToastProps.md +1 -1
  140. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  141. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  142. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  143. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  144. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  145. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  146. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  147. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  148. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  149. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  150. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  151. package/docs/api/interfaces/UserEventAccess.md +1 -1
  152. package/docs/api/interfaces/UserMenuProps.md +1 -1
  153. package/docs/api/interfaces/UserProfile.md +1 -1
  154. package/docs/api/modules.md +84 -15
  155. package/docs/architecture/README.md +0 -1
  156. package/docs/styles/README.md +0 -2
  157. package/examples/RBAC/CompleteRBACExample.tsx +324 -0
  158. package/examples/RBAC/EventBasedApp.tsx +239 -0
  159. package/examples/RBAC/PermissionExample.tsx +151 -0
  160. package/examples/RBAC/index.ts +13 -0
  161. package/examples/public-pages/CorrectPublicPageImplementation.tsx +301 -0
  162. package/examples/public-pages/PublicEventPage.tsx +274 -0
  163. package/examples/public-pages/PublicPageApp.tsx +308 -0
  164. package/examples/public-pages/PublicPageUsageExample.tsx +216 -0
  165. package/examples/public-pages/index.ts +14 -0
  166. package/package.json +1 -10
  167. package/src/__tests__/TEST_STANDARD.md +92 -0
  168. package/src/components/Badge/Badge.test.tsx +314 -0
  169. package/src/components/Badge/Badge.tsx +304 -0
  170. package/src/components/Badge/index.ts +3 -0
  171. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +217 -0
  172. package/src/components/DataTable/__tests__/styles.test.ts +1 -1
  173. package/src/components/DataTable/components/ColumnFilter.tsx +8 -4
  174. package/src/components/DataTable/components/DataTableBody.tsx +461 -0
  175. package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
  176. package/src/components/DataTable/components/FilterRow.tsx +9 -3
  177. package/src/components/DataTable/components/PaginationControls.tsx +1 -0
  178. package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
  179. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +14 -68
  180. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +62 -0
  181. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +43 -0
  182. package/src/components/DataTable/core/ActionManager.ts +235 -0
  183. package/src/components/DataTable/core/ColumnManager.ts +205 -0
  184. package/src/components/DataTable/core/DataManager.ts +188 -0
  185. package/src/components/DataTable/core/DataTableContext.tsx +181 -0
  186. package/src/components/DataTable/core/LocalDataAdapter.ts +273 -0
  187. package/src/components/DataTable/core/PluginRegistry.ts +229 -0
  188. package/src/components/DataTable/core/StateManager.ts +311 -0
  189. package/src/components/DataTable/core/interfaces.ts +338 -0
  190. package/src/components/DataTable/styles.ts +27 -6
  191. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +94 -0
  192. package/src/components/DataTable/utils/columnUtils.ts +40 -0
  193. package/src/components/DataTable/utils/debugTools.ts +609 -0
  194. package/src/components/DataTable/utils/index.ts +1 -0
  195. package/src/components/Dialog/README.md +804 -0
  196. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
  197. package/src/components/Dialog/utils/safeHtml.ts +185 -0
  198. package/src/components/Footer/Footer.test.tsx +1 -1
  199. package/src/components/Form/Form.test.tsx +1 -1
  200. package/src/components/Form/FormErrorSummary.tsx +113 -0
  201. package/src/components/Form/FormFieldset.tsx +127 -0
  202. package/src/components/Form/FormLiveRegion.tsx +198 -0
  203. package/src/components/LoginForm/LoginForm.test.tsx +1 -1
  204. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +76 -10
  205. package/src/components/PaceLoginPage/PaceLoginPage.tsx +1 -1
  206. package/src/components/PasswordReset/PasswordResetForm.test.tsx +597 -0
  207. package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
  208. package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
  209. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
  210. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
  211. package/src/components/Select/Select.test.tsx +1 -1
  212. package/src/components/Select/Select.tsx +20 -8
  213. package/src/components/Table/__tests__/Table.test.tsx +1 -1
  214. package/src/components/index.ts +3 -0
  215. package/src/hooks/__tests__/useFileUrl.unit.test.ts +83 -85
  216. package/src/index.ts +4 -0
  217. package/src/rbac/hooks/useCan.test.ts +24 -0
  218. package/src/rbac/hooks/usePermissions.ts +49 -12
  219. package/src/styles/core.css +3 -0
  220. package/src/utils/appConfig.ts +47 -0
  221. package/src/utils/appIdResolver.test.ts +499 -0
  222. package/src/utils/appIdResolver.ts +130 -0
  223. package/src/utils/appNameResolver.simple.test.ts +212 -0
  224. package/src/utils/appNameResolver.test.ts +121 -0
  225. package/src/utils/appNameResolver.ts +191 -0
  226. package/src/utils/audit.ts +127 -0
  227. package/src/utils/auth-utils.ts +96 -0
  228. package/src/utils/bundleAnalysis.ts +129 -0
  229. package/src/utils/cn.ts +7 -0
  230. package/src/utils/debugLogger.ts +67 -0
  231. package/src/utils/deviceFingerprint.ts +215 -0
  232. package/src/utils/dynamicUtils.ts +105 -0
  233. package/src/utils/file-reference.test.ts +788 -0
  234. package/src/utils/file-reference.ts +519 -0
  235. package/src/utils/formatDate.test.ts +237 -0
  236. package/src/utils/formatting.ts +133 -0
  237. package/src/utils/index.ts +7 -0
  238. package/src/utils/lazyLoad.tsx +44 -0
  239. package/src/utils/logger.ts +179 -0
  240. package/src/utils/organisationContext.test.ts +322 -0
  241. package/src/utils/organisationContext.ts +153 -0
  242. package/src/utils/performanceBenchmark.ts +64 -0
  243. package/src/utils/performanceBudgets.ts +110 -0
  244. package/src/utils/permissionTypes.ts +37 -0
  245. package/src/utils/permissionUtils.test.ts +393 -0
  246. package/src/utils/permissionUtils.ts +34 -0
  247. package/src/utils/sanitization.ts +264 -0
  248. package/src/utils/schemaUtils.ts +37 -0
  249. package/src/utils/secureDataAccess.test.ts +711 -0
  250. package/src/utils/secureDataAccess.ts +377 -0
  251. package/src/utils/secureErrors.ts +79 -0
  252. package/src/utils/secureStorage.ts +244 -0
  253. package/src/utils/security.ts +156 -0
  254. package/src/utils/securityMonitor.ts +45 -0
  255. package/src/utils/sessionTracking.ts +126 -0
  256. package/src/utils/validation.ts +111 -0
  257. package/src/utils/validationUtils.ts +120 -0
  258. package/src/validation/index.ts +2 -2
  259. package/dist/chunk-444EZN6N.js.map +0 -1
  260. package/dist/chunk-APIBCTL2.js +0 -670
  261. package/dist/chunk-APIBCTL2.js.map +0 -1
  262. package/dist/chunk-HJGGOMQ6.js.map +0 -1
  263. package/dist/chunk-K2WWTH7O.js +0 -94
  264. package/dist/chunk-K2WWTH7O.js.map +0 -1
  265. package/dist/chunk-L6PGMCMD.js.map +0 -1
  266. package/dist/chunk-LMC26NLJ.js +0 -84
  267. package/dist/chunk-LMC26NLJ.js.map +0 -1
  268. package/dist/chunk-NOHEVYVX.js.map +0 -1
  269. package/dist/chunk-TVYPTYOY.js.map +0 -1
  270. package/dist/validation-8npbysjg.d.ts +0 -177
  271. /package/dist/{DataTable-CYOHOX3O.js.map → DataTable-JXFCA2BJ.js.map} +0 -0
  272. /package/dist/{UnifiedAuthProvider-5E5TUNMS.js.map → UnifiedAuthProvider-XIQQ7LVU.js.map} +0 -0
  273. /package/dist/{chunk-YLKIDTUK.js.map → chunk-22WKWKRX.js.map} +0 -0
  274. /package/dist/{chunk-FHWWBIHA.js.map → chunk-6DXZ6V5Q.js.map} +0 -0
  275. /package/dist/{chunk-2TWNJ46Y.js.map → chunk-6LAAY47Q.js.map} +0 -0
  276. /package/dist/{chunk-XARJS7CD.js.map → chunk-INQLMHPF.js.map} +0 -0
  277. /package/dist/{chunk-SL2YQDR6.js.map → chunk-MA6EPSGZ.js.map} +0 -0
  278. /package/dist/{chunk-5DPZ5EAT.js.map → chunk-OWAG3GSU.js.map} +0 -0
  279. /package/dist/{chunk-LTV3XIJJ.js.map → chunk-T6JN6LH6.js.map} +0 -0
  280. /package/examples/{components → components 2}/DataTable/HierarchicalActionsExample.tsx +0 -0
  281. /package/examples/{components → components 2}/DataTable/HierarchicalExample.tsx +0 -0
  282. /package/examples/{components → components 2}/DataTable/InitialPageSizeExample.tsx +0 -0
  283. /package/examples/{components → components 2}/DataTable/PerformanceExample.tsx +0 -0
  284. /package/examples/{components → components 2}/DataTable/index.ts +0 -0
  285. /package/examples/{components → components 2}/Dialog/BasicHtmlTest.tsx +0 -0
  286. /package/examples/{components → components 2}/Dialog/DebugHtmlExample.tsx +0 -0
  287. /package/examples/{components → components 2}/Dialog/HtmlDialogExample.tsx +0 -0
  288. /package/examples/{components → components 2}/Dialog/ScrollableDialogExample.tsx +0 -0
  289. /package/examples/{components → components 2}/Dialog/SimpleHtmlTest.tsx +0 -0
  290. /package/examples/{components → components 2}/Dialog/SmartDialogExample.tsx +0 -0
  291. /package/examples/{components → components 2}/Dialog/index.ts +0 -0
  292. /package/examples/{components → components 2}/index.ts +0 -0
@@ -0,0 +1,324 @@
1
+ /**
2
+ * @file Complete RBAC Example
3
+ * @package @jmruthers/pace-core
4
+ * @module Examples/RBAC/CompleteRBACExample
5
+ * @since 2.0.0
6
+ *
7
+ * A comprehensive example showing how to use the new centralized RBAC system
8
+ * with all Phase 1 and Phase 2 components.
9
+ *
10
+ * This example demonstrates:
11
+ * - Page-level permission enforcement
12
+ * - Data access control
13
+ * - Permission enforcement
14
+ * - Role-based routing
15
+ * - Navigation control
16
+ * - Strict mode enforcement
17
+ * - Audit logging
18
+ */
19
+
20
+ import React from 'react';
21
+ import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom';
22
+ import {
23
+ PagePermissionProvider,
24
+ PagePermissionGuard,
25
+ SecureDataProvider,
26
+ PermissionEnforcer,
27
+ RoleBasedRouter,
28
+ NavigationProvider,
29
+ NavigationGuard,
30
+ EnhancedNavigationMenu,
31
+ type NavigationItem,
32
+ type RouteConfig
33
+ } from '../../src/rbac/components';
34
+
35
+ // Example navigation items
36
+ const navigationItems: NavigationItem[] = [
37
+ {
38
+ id: 'dashboard',
39
+ label: 'Dashboard',
40
+ path: '/dashboard',
41
+ permissions: ['read:page.dashboard'],
42
+ meta: { icon: '🏠', description: 'Main dashboard' }
43
+ },
44
+ {
45
+ id: 'events',
46
+ label: 'Events',
47
+ path: '/events',
48
+ permissions: ['read:page.events'],
49
+ meta: { icon: '📅', description: 'Event management' }
50
+ },
51
+ {
52
+ id: 'admin',
53
+ label: 'Admin',
54
+ path: '/admin',
55
+ permissions: ['read:page.admin', 'create:page.admin', 'update:page.admin', 'delete:page.admin'],
56
+ roles: ['admin'],
57
+ accessLevel: 'admin',
58
+ meta: { icon: '⚙️', description: 'Administration' }
59
+ },
60
+ {
61
+ id: 'settings',
62
+ label: 'Settings',
63
+ path: '/settings',
64
+ permissions: ['update:page.settings'],
65
+ meta: { icon: '🔧', description: 'Application settings' }
66
+ }
67
+ ];
68
+
69
+ // Example route configuration
70
+ const routeConfig: RouteConfig[] = [
71
+ {
72
+ path: '/dashboard',
73
+ component: DashboardPage,
74
+ permissions: ['read:page.dashboard'],
75
+ meta: { title: 'Dashboard', requiresAuth: true }
76
+ },
77
+ {
78
+ path: '/events',
79
+ component: EventsPage,
80
+ permissions: ['read:page.events'],
81
+ meta: { title: 'Events', requiresAuth: true }
82
+ },
83
+ {
84
+ path: '/admin',
85
+ component: AdminPage,
86
+ permissions: ['read:page.admin', 'create:page.admin', 'update:page.admin', 'delete:page.admin'],
87
+ roles: ['admin'],
88
+ accessLevel: 'admin',
89
+ strictMode: true,
90
+ meta: { title: 'Admin', requiresAuth: true, hidden: true }
91
+ },
92
+ {
93
+ path: '/settings',
94
+ component: SettingsPage,
95
+ permissions: ['update:page.settings'],
96
+ meta: { title: 'Settings', requiresAuth: true }
97
+ }
98
+ ];
99
+
100
+ // Example page components
101
+ function DashboardPage() {
102
+ return (
103
+ <PagePermissionGuard
104
+ pageName="dashboard"
105
+ operation="read"
106
+ fallback={<AccessDeniedPage />}
107
+ >
108
+ <div className="p-6">
109
+ <h1 className="text-2xl font-bold mb-4">Dashboard</h1>
110
+ <p>Welcome to your dashboard!</p>
111
+
112
+ {/* Example of permission enforcement within a page */}
113
+ <PermissionEnforcer
114
+ permissions={['read:data.events']}
115
+ operation="view-events"
116
+ fallback={<div>You don't have permission to view events</div>}
117
+ >
118
+ <EventsList />
119
+ </PermissionEnforcer>
120
+ </div>
121
+ </PagePermissionGuard>
122
+ );
123
+ }
124
+
125
+ function EventsPage() {
126
+ return (
127
+ <PagePermissionGuard
128
+ pageName="events"
129
+ operation="read"
130
+ fallback={<AccessDeniedPage />}
131
+ >
132
+ <div className="p-6">
133
+ <h1 className="text-2xl font-bold mb-4">Events</h1>
134
+ <EventsList />
135
+ </div>
136
+ </PagePermissionGuard>
137
+ );
138
+ }
139
+
140
+ function AdminPage() {
141
+ return (
142
+ <PagePermissionGuard
143
+ pageName="admin"
144
+ operation="read"
145
+ strictMode={true}
146
+ fallback={<AccessDeniedPage />}
147
+ >
148
+ <div className="p-6">
149
+ <h1 className="text-2xl font-bold mb-4">Admin Panel</h1>
150
+ <p>Administrative functions</p>
151
+
152
+ {/* Example of multiple permission enforcement */}
153
+ <PermissionEnforcer
154
+ permissions={['read:data.users', 'create:data.users', 'update:data.users', 'delete:data.users', 'read:data.organisations', 'create:data.organisations', 'update:data.organisations', 'delete:data.organisations']}
155
+ operation="user-management"
156
+ requireAll={true}
157
+ fallback={<div>You need both user and organisation management permissions</div>}
158
+ >
159
+ <UserManagementPanel />
160
+ </PermissionEnforcer>
161
+ </div>
162
+ </PagePermissionGuard>
163
+ );
164
+ }
165
+
166
+ function SettingsPage() {
167
+ return (
168
+ <PagePermissionGuard
169
+ pageName="settings"
170
+ operation="read"
171
+ fallback={<AccessDeniedPage />}
172
+ >
173
+ <div className="p-6">
174
+ <h1 className="text-2xl font-bold mb-4">Settings</h1>
175
+ <p>Application settings</p>
176
+ </div>
177
+ </PagePermissionGuard>
178
+ );
179
+ }
180
+
181
+ function EventsList() {
182
+ return (
183
+ <div className="bg-main-50 p-4 rounded-lg shadow">
184
+ <h2 className="text-lg font-semibold mb-2">Events</h2>
185
+ <p>List of events would go here...</p>
186
+ </div>
187
+ );
188
+ }
189
+
190
+ function UserManagementPanel() {
191
+ return (
192
+ <div className="bg-main-50 p-4 rounded-lg shadow">
193
+ <h2 className="text-lg font-semibold mb-2">User Management</h2>
194
+ <p>User management functions would go here...</p>
195
+ </div>
196
+ );
197
+ }
198
+
199
+ function AccessDeniedPage() {
200
+ return (
201
+ <div className="flex flex-col items-center justify-center min-h-screen p-8 text-center">
202
+ <div className="mb-4">
203
+ <svg className="w-16 h-16 text-acc-500 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
204
+ <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
205
+ </svg>
206
+ </div>
207
+ <h2 className="text-xl font-semibold text-sec-900 mb-2">Access Denied</h2>
208
+ <p className="text-sec-600 mb-4">You don't have permission to access this page.</p>
209
+ <button
210
+ onClick={() => window.history.back()}
211
+ className="px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors"
212
+ >
213
+ Go Back
214
+ </button>
215
+ </div>
216
+ );
217
+ }
218
+
219
+ function AppLayout({ children }: { children: React.ReactNode }) {
220
+ return (
221
+ <div className="min-h-screen bg-sec-50">
222
+ <header className="bg-main-50 shadow-sm border-b">
223
+ <div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
224
+ <div className="flex justify-between items-center h-16">
225
+ <div className="flex items-center">
226
+ <h1 className="text-xl font-semibold">PACE Core RBAC Example</h1>
227
+ </div>
228
+
229
+ {/* Enhanced Navigation Menu */}
230
+ <EnhancedNavigationMenu
231
+ items={navigationItems}
232
+ strictMode={true}
233
+ auditLog={true}
234
+ className="flex space-x-4"
235
+ itemClassName="px-3 py-2 rounded-md text-sm font-medium transition-colors hover:bg-sec-100"
236
+ activeItemClassName="bg-main-100 text-main-700"
237
+ onNavigationAccess={(item, allowed) => {
238
+ console.log(`Navigation access: ${item.id} - ${allowed ? 'allowed' : 'denied'}`);
239
+ }}
240
+ />
241
+ </div>
242
+ </div>
243
+ </header>
244
+
245
+ <main className="max-w-7xl mx-auto py-6 sm:px-6 lg:px-8">
246
+ {children}
247
+ </main>
248
+ </div>
249
+ );
250
+ }
251
+
252
+ /**
253
+ * Complete RBAC Example Application
254
+ *
255
+ * This example shows how to use all the new RBAC components together
256
+ * to create a secure, centralized permission system.
257
+ */
258
+ export function CompleteRBACExample() {
259
+ return (
260
+ <Router>
261
+ {/* Phase 1: Core Security Enforcement */}
262
+ <PagePermissionProvider
263
+ strictMode={true}
264
+ auditLog={true}
265
+ onPageAccess={(pageName, operation, allowed) => {
266
+ console.log(`Page access: ${pageName} ${operation} - ${allowed ? 'allowed' : 'denied'}`);
267
+ }}
268
+ onStrictModeViolation={(pageName, operation) => {
269
+ console.error(`Strict mode violation: ${pageName} ${operation}`);
270
+ }}
271
+ >
272
+ <SecureDataProvider
273
+ strictMode={true}
274
+ auditLog={true}
275
+ onDataAccess={(table, operation, allowed) => {
276
+ console.log(`Data access: ${table} ${operation} - ${allowed ? 'allowed' : 'denied'}`);
277
+ }}
278
+ onStrictModeViolation={(table, operation) => {
279
+ console.error(`Data access violation: ${table} ${operation}`);
280
+ }}
281
+ >
282
+ {/* Phase 2: Routing and Navigation */}
283
+ <NavigationProvider
284
+ strictMode={true}
285
+ auditLog={true}
286
+ onNavigationAccess={(item, allowed) => {
287
+ console.log(`Navigation access: ${item.id} - ${allowed ? 'allowed' : 'denied'}`);
288
+ }}
289
+ onStrictModeViolation={(item) => {
290
+ console.error(`Navigation violation: ${item.id}`);
291
+ }}
292
+ >
293
+ <RoleBasedRouter
294
+ routes={routeConfig}
295
+ fallbackRoute="/unauthorized"
296
+ strictMode={true}
297
+ auditLog={true}
298
+ onRouteAccess={(route, allowed) => {
299
+ console.log(`Route access: ${route} - ${allowed ? 'allowed' : 'denied'}`);
300
+ }}
301
+ onStrictModeViolation={(route) => {
302
+ console.error(`Route violation: ${route}`);
303
+ }}
304
+ >
305
+ <AppLayout>
306
+ <Routes>
307
+ <Route path="/" element={<Navigate to="/dashboard" replace />} />
308
+ <Route path="/dashboard" element={<DashboardPage />} />
309
+ <Route path="/events" element={<EventsPage />} />
310
+ <Route path="/admin" element={<AdminPage />} />
311
+ <Route path="/settings" element={<SettingsPage />} />
312
+ <Route path="/unauthorized" element={<AccessDeniedPage />} />
313
+ </Routes>
314
+ </AppLayout>
315
+ </RoleBasedRouter>
316
+ </NavigationProvider>
317
+ </SecureDataProvider>
318
+ </PagePermissionProvider>
319
+ </Router>
320
+ );
321
+ }
322
+
323
+ export default CompleteRBACExample;
324
+
@@ -0,0 +1,239 @@
1
+ /**
2
+ * Event-Based App Example
3
+ * @package @jmruthers/pace-core
4
+ * @module Examples/RBAC/EventBasedApp
5
+ * @since 1.0.0
6
+ *
7
+ * This example demonstrates how to build an event-based app using the RBAC system.
8
+ */
9
+
10
+ import React from 'react';
11
+ import {
12
+ PermissionEnforcer,
13
+ PagePermissionGuard,
14
+ NavigationGuard,
15
+ useCan
16
+ } from '../../src/rbac';
17
+ import { useUnifiedAuth } from '../../src/providers';
18
+ import type { Permission } from '../../src/rbac/types';
19
+
20
+ // Example navigation items for an event-based app
21
+ const navigationItems = [
22
+ {
23
+ id: 'dashboard',
24
+ name: 'Dashboard',
25
+ label: 'Dashboard',
26
+ path: '/event/dashboard',
27
+ permissions: ['read:events'] as Permission[],
28
+ },
29
+ {
30
+ id: 'participants',
31
+ name: 'Participants',
32
+ label: 'Participants',
33
+ path: '/event/participants',
34
+ permissions: ['read:participants'] as Permission[],
35
+ },
36
+ {
37
+ id: 'settings',
38
+ name: 'Settings',
39
+ label: 'Settings',
40
+ path: '/event/settings',
41
+ permissions: ['read:events', 'create:events', 'update:events', 'delete:events'] as Permission[],
42
+ },
43
+ ];
44
+
45
+ // Example event dashboard component
46
+ function EventDashboard() {
47
+ const { user, selectedEventId } = useUnifiedAuth();
48
+
49
+ return (
50
+ <div className="event-dashboard">
51
+ <h1>Event Dashboard</h1>
52
+ <p>Event ID: {selectedEventId}</p>
53
+
54
+ {/* Example of using useCan hook with event context */}
55
+ <PermissionEnforcer
56
+ permissions={['read:events']}
57
+ operation="dashboard"
58
+ >
59
+ <div className="dashboard-content">
60
+ <h2>Event Overview</h2>
61
+ <p>Welcome to the event dashboard!</p>
62
+ </div>
63
+ </PermissionEnforcer>
64
+
65
+ {/* Example of conditional rendering based on permissions */}
66
+ <PermissionEnforcer
67
+ permissions={['read:events', 'create:events', 'update:events', 'delete:events']}
68
+ operation="event-management"
69
+ >
70
+ <div className="admin-controls">
71
+ <h3>Admin Controls</h3>
72
+ <button>Edit Event</button>
73
+ <button>Delete Event</button>
74
+ </div>
75
+ </PermissionEnforcer>
76
+ </div>
77
+ );
78
+ }
79
+
80
+ // Example participants page component
81
+ function ParticipantsPage() {
82
+ return (
83
+ <PagePermissionGuard
84
+ pageName="participants"
85
+ operation="read"
86
+ >
87
+ <div className="participants-page">
88
+ <h1>Participants</h1>
89
+ <p>Manage event participants here.</p>
90
+
91
+ <PermissionEnforcer
92
+ permissions={['create:participants']}
93
+ operation="add-participant"
94
+ >
95
+ <button>Add Participant</button>
96
+ </PermissionEnforcer>
97
+
98
+ <PermissionEnforcer
99
+ permissions={['delete:participants']}
100
+ operation="remove-participant"
101
+ >
102
+ <button>Remove Participant</button>
103
+ </PermissionEnforcer>
104
+ </div>
105
+ </PagePermissionGuard>
106
+ );
107
+ }
108
+
109
+ // Example settings page component
110
+ function SettingsPage() {
111
+ return (
112
+ <PagePermissionGuard
113
+ pageName="settings"
114
+ operation="read"
115
+ >
116
+ <div className="settings-page">
117
+ <h1>Event Settings</h1>
118
+ <p>Configure event settings here.</p>
119
+
120
+ <PermissionEnforcer
121
+ permissions={['update:events']}
122
+ operation="update-settings"
123
+ >
124
+ <form>
125
+ <label>
126
+ Event Name:
127
+ <input type="text" />
128
+ </label>
129
+ <button type="submit">Save Changes</button>
130
+ </form>
131
+ </PermissionEnforcer>
132
+ </div>
133
+ </PagePermissionGuard>
134
+ );
135
+ }
136
+
137
+ // Example navigation component
138
+ function EventNavigation() {
139
+ return (
140
+ <nav className="event-navigation">
141
+ <ul>
142
+ {navigationItems.map(item => (
143
+ <li key={item.id}>
144
+ <NavigationGuard
145
+ navigationItem={item}
146
+ fallback={<span className="disabled">{item.name}</span>}
147
+ >
148
+ <a href={item.path}>{item.name}</a>
149
+ </NavigationGuard>
150
+ </li>
151
+ ))}
152
+ </ul>
153
+ </nav>
154
+ );
155
+ }
156
+
157
+ // Example main app component
158
+ export function EventBasedApp() {
159
+ const { selectedEventId, user } = useUnifiedAuth();
160
+
161
+ // Show loading state if no event is selected
162
+ if (!selectedEventId) {
163
+ return (
164
+ <div className="event-app">
165
+ <h1>Event-Based App</h1>
166
+ <p>Please select an event to continue.</p>
167
+ </div>
168
+ );
169
+ }
170
+
171
+ // Show loading state if no user is authenticated
172
+ if (!user) {
173
+ return (
174
+ <div className="event-app">
175
+ <h1>Event-Based App</h1>
176
+ <p>Please log in to continue.</p>
177
+ </div>
178
+ );
179
+ }
180
+
181
+ return (
182
+ <div className="event-app">
183
+ <header>
184
+ <h1>Event-Based App</h1>
185
+ <p>User: {user.email}</p>
186
+ <p>Event: {selectedEventId}</p>
187
+ </header>
188
+
189
+ <EventNavigation />
190
+
191
+ <main>
192
+ <EventDashboard />
193
+ <ParticipantsPage />
194
+ <SettingsPage />
195
+ </main>
196
+ </div>
197
+ );
198
+ }
199
+
200
+ // Example of using the app with different permission scenarios
201
+ export function EventBasedAppWithCustomScope() {
202
+ const { user } = useUnifiedAuth();
203
+
204
+ // Example of providing explicit scope
205
+ const customScope = {
206
+ eventId: 'event-123',
207
+ appId: 'app-456'
208
+ };
209
+
210
+ return (
211
+ <div className="event-app">
212
+ <h1>Event-Based App with Custom Scope</h1>
213
+
214
+ <PermissionEnforcer
215
+ scope={customScope}
216
+ permissions={['read:events']}
217
+ operation="custom-scope-example"
218
+ >
219
+ <div>
220
+ <p>This content is shown when the user has read:events permission</p>
221
+ <p>for event-123 in app-456.</p>
222
+ </div>
223
+ </PermissionEnforcer>
224
+
225
+ <PermissionEnforcer
226
+ scope={customScope}
227
+ permissions={['read:events', 'create:events', 'update:events', 'delete:events']}
228
+ operation="admin-example"
229
+ fallback={<p>You don't have admin permissions for this event.</p>}
230
+ >
231
+ <div>
232
+ <p>This content is shown when the user has events permissions</p>
233
+ <p>for event-123 in app-456.</p>
234
+ </div>
235
+ </PermissionEnforcer>
236
+ </div>
237
+ );
238
+ }
239
+