@jmruthers/pace-core 0.5.109 → 0.5.111

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 (240) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/dist/{AuthService-DrHrvXNZ.d.ts → AuthService-CVgsgtaZ.d.ts} +8 -0
  3. package/dist/{DataTable-5HITILXS.js → DataTable-5W2HVLLV.js} +8 -8
  4. package/dist/{UnifiedAuthProvider-A7I23UCN.js → UnifiedAuthProvider-LUM3QLS5.js} +3 -3
  5. package/dist/{api-5I3E47G2.js → api-SIZPFBFX.js} +5 -3
  6. package/dist/{audit-65VNHEV2.js → audit-5JI5T3SL.js} +2 -2
  7. package/dist/{chunk-P72NKAT5.js → chunk-2BIDKXQU.js} +157 -120
  8. package/dist/chunk-2BIDKXQU.js.map +1 -0
  9. package/dist/{chunk-S4D3Z723.js → chunk-ACYQNYHB.js} +7 -7
  10. package/dist/{chunk-D6MEKC27.js → chunk-EFVQBYFN.js} +2 -2
  11. package/dist/{chunk-EZ64QG2I.js → chunk-I5YM5BGS.js} +2 -2
  12. package/dist/{chunk-Q7APDV6H.js → chunk-IWJYNWXN.js} +13 -5
  13. package/dist/chunk-IWJYNWXN.js.map +1 -0
  14. package/dist/{chunk-YFMENCR4.js → chunk-JE2GFA3O.js} +3 -3
  15. package/dist/{chunk-AUXS7XSO.js → chunk-MW73E7SP.js} +35 -11
  16. package/dist/chunk-MW73E7SP.js.map +1 -0
  17. package/dist/{chunk-F6TSYCKP.js → chunk-PXXS26G5.js} +68 -29
  18. package/dist/chunk-PXXS26G5.js.map +1 -0
  19. package/dist/{chunk-UW2DE6JX.js → chunk-TD4BXGPE.js} +4 -4
  20. package/dist/{chunk-EYSXQ756.js → chunk-TDFBX7KJ.js} +2 -2
  21. package/dist/{chunk-WWNOVFDC.js → chunk-UGVU7L7N.js} +52 -90
  22. package/dist/chunk-UGVU7L7N.js.map +1 -0
  23. package/dist/{chunk-2W4WKJVF.js → chunk-X7SPKHYZ.js} +290 -255
  24. package/dist/chunk-X7SPKHYZ.js.map +1 -0
  25. package/dist/{chunk-3TKTL5AZ.js → chunk-ZL45MG76.js} +60 -60
  26. package/dist/chunk-ZL45MG76.js.map +1 -0
  27. package/dist/components.js +10 -10
  28. package/dist/hooks.d.ts +11 -1
  29. package/dist/hooks.js +9 -7
  30. package/dist/hooks.js.map +1 -1
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +13 -13
  33. package/dist/providers.d.ts +2 -2
  34. package/dist/providers.js +2 -2
  35. package/dist/rbac/index.d.ts +46 -29
  36. package/dist/rbac/index.js +9 -9
  37. package/dist/utils.js +1 -1
  38. package/docs/api/classes/ColumnFactory.md +1 -1
  39. package/docs/api/classes/ErrorBoundary.md +1 -1
  40. package/docs/api/classes/InvalidScopeError.md +4 -4
  41. package/docs/api/classes/MissingUserContextError.md +4 -4
  42. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  43. package/docs/api/classes/PermissionDeniedError.md +4 -4
  44. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  45. package/docs/api/classes/RBACAuditManager.md +8 -8
  46. package/docs/api/classes/RBACCache.md +8 -8
  47. package/docs/api/classes/RBACEngine.md +9 -8
  48. package/docs/api/classes/RBACError.md +4 -4
  49. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  50. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  51. package/docs/api/classes/StorageUtils.md +1 -1
  52. package/docs/api/enums/FileCategory.md +1 -1
  53. package/docs/api/interfaces/AggregateConfig.md +1 -1
  54. package/docs/api/interfaces/ButtonProps.md +1 -1
  55. package/docs/api/interfaces/CardProps.md +1 -1
  56. package/docs/api/interfaces/ColorPalette.md +1 -1
  57. package/docs/api/interfaces/ColorShade.md +1 -1
  58. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  59. package/docs/api/interfaces/DataRecord.md +1 -1
  60. package/docs/api/interfaces/DataTableAction.md +1 -1
  61. package/docs/api/interfaces/DataTableColumn.md +1 -1
  62. package/docs/api/interfaces/DataTableProps.md +1 -1
  63. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  64. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  65. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  66. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  67. package/docs/api/interfaces/FileMetadata.md +1 -1
  68. package/docs/api/interfaces/FileReference.md +1 -1
  69. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  70. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  71. package/docs/api/interfaces/FileUploadProps.md +1 -1
  72. package/docs/api/interfaces/FooterProps.md +1 -1
  73. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  74. package/docs/api/interfaces/InputProps.md +1 -1
  75. package/docs/api/interfaces/LabelProps.md +1 -1
  76. package/docs/api/interfaces/LoginFormProps.md +1 -1
  77. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  78. package/docs/api/interfaces/NavigationContextType.md +1 -1
  79. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  80. package/docs/api/interfaces/NavigationItem.md +1 -1
  81. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  82. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  83. package/docs/api/interfaces/Organisation.md +1 -1
  84. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  85. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  86. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  87. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  88. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  89. package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
  90. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  91. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  92. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  93. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  94. package/docs/api/interfaces/PaletteData.md +1 -1
  95. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  96. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  97. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  98. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  99. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  100. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  101. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  102. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  103. package/docs/api/interfaces/RBACConfig.md +19 -8
  104. package/docs/api/interfaces/RBACLogger.md +5 -5
  105. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  106. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  107. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  108. package/docs/api/interfaces/RouteConfig.md +19 -6
  109. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  110. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  111. package/docs/api/interfaces/StorageConfig.md +1 -1
  112. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  113. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  114. package/docs/api/interfaces/StorageListOptions.md +1 -1
  115. package/docs/api/interfaces/StorageListResult.md +1 -1
  116. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  117. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  118. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  119. package/docs/api/interfaces/StyleImport.md +1 -1
  120. package/docs/api/interfaces/SwitchProps.md +1 -1
  121. package/docs/api/interfaces/ToastActionElement.md +1 -1
  122. package/docs/api/interfaces/ToastProps.md +1 -1
  123. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  124. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  125. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  126. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  127. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  128. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  129. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  130. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  131. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  132. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  133. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  134. package/docs/api/interfaces/UserEventAccess.md +1 -1
  135. package/docs/api/interfaces/UserMenuProps.md +1 -1
  136. package/docs/api/interfaces/UserProfile.md +1 -1
  137. package/docs/api/modules.md +44 -43
  138. package/docs/api-reference/hooks.md +8 -4
  139. package/docs/architecture/rpc-function-standards.md +3 -1
  140. package/docs/best-practices/common-patterns.md +3 -3
  141. package/docs/best-practices/deployment.md +10 -4
  142. package/docs/best-practices/performance.md +11 -3
  143. package/docs/core-concepts/organisations.md +8 -8
  144. package/docs/core-concepts/permissions.md +133 -72
  145. package/docs/documentation-index.md +0 -2
  146. package/docs/migration/rbac-migration.md +65 -66
  147. package/docs/rbac/README.md +114 -38
  148. package/docs/rbac/advanced-patterns.md +15 -22
  149. package/docs/rbac/api-reference.md +63 -16
  150. package/docs/rbac/examples.md +12 -12
  151. package/docs/rbac/getting-started.md +19 -19
  152. package/docs/rbac/quick-start.md +110 -35
  153. package/docs/rbac/troubleshooting.md +127 -3
  154. package/package.json +1 -1
  155. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +913 -0
  156. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +609 -0
  157. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +434 -0
  158. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +120 -0
  159. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +519 -0
  160. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +316 -0
  161. package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +211 -0
  162. package/src/components/FileUpload/FileUpload.tsx +2 -8
  163. package/src/components/NavigationMenu/NavigationMenu.test.tsx +38 -4
  164. package/src/components/NavigationMenu/NavigationMenu.tsx +71 -6
  165. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +193 -63
  166. package/src/components/PaceAppLayout/PaceAppLayout.tsx +102 -135
  167. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +41 -2
  168. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +61 -6
  169. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +71 -21
  170. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +113 -41
  171. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +155 -45
  172. package/src/components/PaceLoginPage/PaceLoginPage.tsx +30 -1
  173. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +63 -5
  174. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +156 -72
  175. package/src/hooks/__tests__/useRBAC.unit.test.ts +4 -38
  176. package/src/hooks/index.ts +1 -1
  177. package/src/hooks/useFileDisplay.ts +51 -0
  178. package/src/hooks/usePermissionCache.test.ts +112 -68
  179. package/src/hooks/usePermissionCache.ts +55 -15
  180. package/src/rbac/README.md +81 -39
  181. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +3 -3
  182. package/src/rbac/__tests__/engine.comprehensive.test.ts +15 -6
  183. package/src/rbac/__tests__/rbac-core.test.tsx +1 -1
  184. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +57 -4
  185. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +3 -2
  186. package/src/rbac/adapters.tsx +4 -4
  187. package/src/rbac/api.test.ts +39 -15
  188. package/src/rbac/api.ts +27 -9
  189. package/src/rbac/audit.test.ts +2 -2
  190. package/src/rbac/audit.ts +14 -5
  191. package/src/rbac/cache.test.ts +12 -0
  192. package/src/rbac/cache.ts +29 -9
  193. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +1 -1
  194. package/src/rbac/components/NavigationGuard.tsx +14 -14
  195. package/src/rbac/components/NavigationProvider.test.tsx +1 -1
  196. package/src/rbac/components/PagePermissionGuard.tsx +22 -38
  197. package/src/rbac/components/PagePermissionProvider.test.tsx +1 -1
  198. package/src/rbac/components/PermissionEnforcer.tsx +19 -15
  199. package/src/rbac/components/RoleBasedRouter.tsx +16 -9
  200. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +123 -107
  201. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
  202. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +121 -103
  203. package/src/rbac/config.ts +2 -0
  204. package/src/rbac/docs/event-based-apps.md +6 -6
  205. package/src/rbac/engine.ts +27 -7
  206. package/src/rbac/hooks/useCan.test.ts +29 -2
  207. package/src/rbac/hooks/usePermissions.test.ts +25 -25
  208. package/src/rbac/hooks/usePermissions.ts +47 -23
  209. package/src/rbac/hooks/useRBAC.simple.test.ts +1 -8
  210. package/src/rbac/hooks/useRBAC.test.ts +3 -40
  211. package/src/rbac/hooks/useRBAC.ts +0 -55
  212. package/src/rbac/hooks/useResolvedScope.ts +23 -31
  213. package/src/rbac/permissions.test.ts +11 -7
  214. package/src/rbac/security.test.ts +2 -2
  215. package/src/rbac/security.ts +23 -8
  216. package/src/rbac/types.test.ts +2 -2
  217. package/src/rbac/types.ts +1 -2
  218. package/src/services/EventService.ts +41 -13
  219. package/src/services/__tests__/EventService.test.ts +25 -4
  220. package/src/services/interfaces/IEventService.ts +1 -0
  221. package/src/utils/file-reference.ts +9 -0
  222. package/dist/chunk-2W4WKJVF.js.map +0 -1
  223. package/dist/chunk-3TKTL5AZ.js.map +0 -1
  224. package/dist/chunk-AUXS7XSO.js.map +0 -1
  225. package/dist/chunk-F6TSYCKP.js.map +0 -1
  226. package/dist/chunk-P72NKAT5.js.map +0 -1
  227. package/dist/chunk-Q7APDV6H.js.map +0 -1
  228. package/dist/chunk-WWNOVFDC.js.map +0 -1
  229. package/docs/rbac/breaking-changes-v3.md +0 -222
  230. package/docs/rbac/migration-guide.md +0 -260
  231. /package/dist/{DataTable-5HITILXS.js.map → DataTable-5W2HVLLV.js.map} +0 -0
  232. /package/dist/{UnifiedAuthProvider-A7I23UCN.js.map → UnifiedAuthProvider-LUM3QLS5.js.map} +0 -0
  233. /package/dist/{api-5I3E47G2.js.map → api-SIZPFBFX.js.map} +0 -0
  234. /package/dist/{audit-65VNHEV2.js.map → audit-5JI5T3SL.js.map} +0 -0
  235. /package/dist/{chunk-S4D3Z723.js.map → chunk-ACYQNYHB.js.map} +0 -0
  236. /package/dist/{chunk-D6MEKC27.js.map → chunk-EFVQBYFN.js.map} +0 -0
  237. /package/dist/{chunk-EZ64QG2I.js.map → chunk-I5YM5BGS.js.map} +0 -0
  238. /package/dist/{chunk-YFMENCR4.js.map → chunk-JE2GFA3O.js.map} +0 -0
  239. /package/dist/{chunk-UW2DE6JX.js.map → chunk-TD4BXGPE.js.map} +0 -0
  240. /package/dist/{chunk-EYSXQ756.js.map → chunk-TDFBX7KJ.js.map} +0 -0
package/CHANGELOG.md CHANGED
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.5.110] - 2025-01-27
11
+
12
+ ### Added
13
+ - **Automatic Page Permission Checking in NavigationMenu**: Navigation items with `href` but no explicit permissions/roles/accessLevel now automatically check for `read:page.{pageId}` permission, making navigation filtering more intuitive
14
+ - **RBAC Security Configuration Support**: `RBACEngine` and `createRBACEngine` now accept an optional `securityConfig` parameter, allowing customization of rate limits and security settings per instance
15
+
16
+ ### Changed
17
+ - **RBAC Rate Limit Increase**: Increased default `maxPermissionChecksPerMinute` from 100 to 1000 to accommodate normal application usage patterns
18
+ - **NavigationMenu Filtering Improvements**: Enhanced recursive filtering of navigation items with proper parent/child handling - parents without accessible children are now properly hidden
19
+ - **RBAC Documentation Updates**: Improved RBAC documentation with better examples, troubleshooting guides, and API references
20
+ - **PagePermissionGuard Scope Handling**: Replaced ref-based scope tracking with `useMemo` for better React compatibility and performance, with improved handling of undefined `appId` values
21
+
22
+ ### Fixed
23
+ - **PagePermissionGuard Infinite Loop Prevention**: Fixed potential infinite loops by improving scope stability and ensuring `useCan` only runs with valid scopes
24
+ - **PagePermissionGuard Error Logging**: Enhanced error logging with more context (permission strings, page IDs, scope validation status)
25
+ - **NavigationMenu Test Mocks**: Updated test mocks to default to permissive permissions (super admin access) for better test isolation and clearer test intent
26
+ - **RBAC API Test Assertions**: Fixed test assertions to correctly match `createRBACEngine` function signature with optional parameters
27
+
28
+ ### Removed
29
+ - **pace-core-devtools Package**: Removed the entire `pace-core-devtools` package and all related devtools functionality (AuditInspector, PerformanceMonitor, PermissionDebugger, RoleSimulator, etc.)
30
+ - **Outdated RBAC Documentation**: Removed deprecated `breaking-changes-v3.md` and `migration-guide.md` files that are no longer relevant
31
+
10
32
  ## [0.5.109] - 2025-11-03
11
33
 
12
34
  ### Added
@@ -76,6 +76,7 @@ interface IEventService {
76
76
  setSelectedEvent(event: Event | null): void;
77
77
  refreshEvents(): Promise<void>;
78
78
  loadPersistedEvent(events: Event[]): Promise<boolean>;
79
+ restorePersistedEvent(): Promise<boolean>;
79
80
  persistEventSelection(eventId: string): void;
80
81
  autoSelectNextEvent(events: Event[]): void;
81
82
  initialize(): Promise<void>;
@@ -116,6 +117,13 @@ declare class EventService extends BaseService implements IEventService {
116
117
  setSelectedEvent(event: Event | null): void;
117
118
  refreshEvents(): Promise<void>;
118
119
  loadPersistedEvent(events: Event[]): Promise<boolean>;
120
+ /**
121
+ * Restore persisted event after login screen has rendered
122
+ * This should be called explicitly from login page component
123
+ *
124
+ * @returns Promise<boolean> - true if event was successfully restored, false otherwise
125
+ */
126
+ restorePersistedEvent(): Promise<boolean>;
119
127
  persistEventSelection(eventId: string): void;
120
128
  clearEventSelection(): void;
121
129
  autoSelectNextEvent(events: Event[]): void;
@@ -54,10 +54,10 @@ import {
54
54
  sortHierarchicalDataWithSorting,
55
55
  validateHierarchicalData,
56
56
  validatePaginationConfig
57
- } from "./chunk-UW2DE6JX.js";
58
- import "./chunk-WWNOVFDC.js";
59
- import "./chunk-F6TSYCKP.js";
60
- import "./chunk-Q7APDV6H.js";
57
+ } from "./chunk-TD4BXGPE.js";
58
+ import "./chunk-UGVU7L7N.js";
59
+ import "./chunk-PXXS26G5.js";
60
+ import "./chunk-IWJYNWXN.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-EZ64QG2I.js";
80
- import "./chunk-EYSXQ756.js";
81
- import "./chunk-AUXS7XSO.js";
79
+ import "./chunk-I5YM5BGS.js";
80
+ import "./chunk-TDFBX7KJ.js";
81
+ import "./chunk-MW73E7SP.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-5HITILXS.js.map
160
+ //# sourceMappingURL=DataTable-5W2HVLLV.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  init_UnifiedAuthProvider
3
- } from "./chunk-EYSXQ756.js";
3
+ } from "./chunk-TDFBX7KJ.js";
4
4
  import {
5
5
  UnifiedAuthProvider,
6
6
  useUnifiedAuth
7
- } from "./chunk-AUXS7XSO.js";
7
+ } from "./chunk-MW73E7SP.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-A7I23UCN.js.map
16
+ //# sourceMappingURL=UnifiedAuthProvider-LUM3QLS5.js.map
@@ -1,4 +1,5 @@
1
1
  import {
2
+ OrganisationContextRequiredError,
2
3
  clearCache,
3
4
  getAccessLevel,
4
5
  getAppConfig,
@@ -19,10 +20,11 @@ import {
19
20
  isSuperAdmin,
20
21
  resolveAppContext,
21
22
  setupRBAC
22
- } from "./chunk-F6TSYCKP.js";
23
- import "./chunk-Q7APDV6H.js";
23
+ } from "./chunk-PXXS26G5.js";
24
+ import "./chunk-IWJYNWXN.js";
24
25
  import "./chunk-PLDDJCW6.js";
25
26
  export {
27
+ OrganisationContextRequiredError,
26
28
  clearCache,
27
29
  getAccessLevel,
28
30
  getAppConfig,
@@ -44,4 +46,4 @@ export {
44
46
  resolveAppContext,
45
47
  setupRBAC
46
48
  };
47
- //# sourceMappingURL=api-5I3E47G2.js.map
49
+ //# sourceMappingURL=api-SIZPFBFX.js.map
@@ -4,7 +4,7 @@ import {
4
4
  emitAuditEvent,
5
5
  getGlobalAuditManager,
6
6
  setGlobalAuditManager
7
- } from "./chunk-Q7APDV6H.js";
7
+ } from "./chunk-IWJYNWXN.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-65VNHEV2.js.map
16
+ //# sourceMappingURL=audit-5JI5T3SL.js.map
@@ -25,16 +25,16 @@ import {
25
25
  SelectSeparator,
26
26
  SelectTrigger,
27
27
  SelectValue
28
- } from "./chunk-UW2DE6JX.js";
28
+ } from "./chunk-TD4BXGPE.js";
29
29
  import {
30
+ useCan,
30
31
  usePermissions,
31
32
  useRBAC,
32
33
  useResolvedScope
33
- } from "./chunk-WWNOVFDC.js";
34
+ } from "./chunk-UGVU7L7N.js";
34
35
  import {
35
- isPermitted,
36
36
  isSuperAdmin
37
- } from "./chunk-F6TSYCKP.js";
37
+ } from "./chunk-PXXS26G5.js";
38
38
  import {
39
39
  OrganisationProvider_exports,
40
40
  PublicErrorBoundary,
@@ -49,18 +49,19 @@ import {
49
49
  useIsPublicPage,
50
50
  usePublicFileDisplay,
51
51
  usePublicPageContext
52
- } from "./chunk-2W4WKJVF.js";
52
+ } from "./chunk-X7SPKHYZ.js";
53
53
  import {
54
54
  useToast
55
55
  } from "./chunk-4OX5PXHX.js";
56
56
  import {
57
+ init_useOrganisations,
57
58
  useEvents,
58
59
  useOrganisations
59
- } from "./chunk-EZ64QG2I.js";
60
+ } from "./chunk-I5YM5BGS.js";
60
61
  import {
61
62
  UnifiedAuthProvider_exports,
62
63
  init_UnifiedAuthProvider as init_UnifiedAuthProvider2
63
- } from "./chunk-EYSXQ756.js";
64
+ } from "./chunk-TDFBX7KJ.js";
64
65
  import {
65
66
  EventServiceContext,
66
67
  EventServiceProvider,
@@ -70,7 +71,7 @@ import {
70
71
  useEventService,
71
72
  useSessionRestoration,
72
73
  useUnifiedAuth
73
- } from "./chunk-AUXS7XSO.js";
74
+ } from "./chunk-MW73E7SP.js";
74
75
  import {
75
76
  LoadingSpinner
76
77
  } from "./chunk-CDQ3PX7L.js";
@@ -929,8 +930,12 @@ var NavigationMenu = React9.forwardRef(({
929
930
  if (!filterByPermissions || !authContext || !rbacContext || scopeLoading || permissionsLoading || !resolvedScope?.organisationId) {
930
931
  return (items || []).filter((item) => !item.meta?.hidden);
931
932
  }
932
- return (items || []).filter((item) => {
933
- if (item.meta?.hidden) return false;
933
+ const getPageIdFromHref = (href) => {
934
+ if (!href) return null;
935
+ const path = href.split("?")[0].split("#")[0].replace(/^\//, "");
936
+ return path || "home";
937
+ };
938
+ const hasItemPermission = (item) => {
934
939
  if (item.permissions && item.permissions.length > 0) {
935
940
  const permissions = item.permissions.filter((p) => typeof p === "string").map((p) => p);
936
941
  if (permissions.length > 0) {
@@ -986,8 +991,43 @@ var NavigationMenu = React9.forwardRef(({
986
991
  }
987
992
  }
988
993
  }
994
+ if (item.href && !item.permissions && !item.roles && !item.accessLevel) {
995
+ const pageId = item.pageId || getPageIdFromHref(item.href);
996
+ if (pageId) {
997
+ const pagePermission = `read:page.${pageId}`;
998
+ const hasPagePermission = permissionMap["*"] === true || permissionMap[pagePermission] === true;
999
+ if (!hasPagePermission) {
1000
+ if (auditLog) {
1001
+ console.log(`[NavigationMenu] Filtering out navigation item "${item.label}" - no page permission:`, {
1002
+ itemId: item.id,
1003
+ href: item.href,
1004
+ pageId,
1005
+ permission: pagePermission,
1006
+ hasPermission: hasPagePermission
1007
+ });
1008
+ }
1009
+ return false;
1010
+ }
1011
+ }
1012
+ }
989
1013
  return true;
990
- });
1014
+ };
1015
+ const filterItem = (item) => {
1016
+ if (item.meta?.hidden) return null;
1017
+ if (!hasItemPermission(item)) return null;
1018
+ let filteredChildren;
1019
+ if (item.children && item.children.length > 0) {
1020
+ filteredChildren = item.children.map((child) => filterItem(child)).filter((child) => child !== null);
1021
+ if (filteredChildren.length === 0 && !item.href) {
1022
+ return null;
1023
+ }
1024
+ }
1025
+ return {
1026
+ ...item,
1027
+ children: filteredChildren
1028
+ };
1029
+ };
1030
+ return (items || []).map((item) => filterItem(item)).filter((item) => item !== null);
991
1031
  }, [
992
1032
  items,
993
1033
  filterByPermissions,
@@ -997,7 +1037,8 @@ var NavigationMenu = React9.forwardRef(({
997
1037
  hasAnyPermission,
998
1038
  scopeLoading,
999
1039
  permissionsLoading,
1000
- resolvedScope
1040
+ resolvedScope,
1041
+ auditLog
1001
1042
  ]);
1002
1043
  React9.useEffect(() => {
1003
1044
  if (auditLog && authContext) {
@@ -1332,7 +1373,8 @@ Footer.displayName = "Footer";
1332
1373
 
1333
1374
  // src/components/PaceAppLayout/PaceAppLayout.tsx
1334
1375
  init_UnifiedAuthProvider2();
1335
- import { useState as useState5, useEffect as useEffect3, useMemo as useMemo5, useCallback as useCallback3 } from "react";
1376
+ init_useOrganisations();
1377
+ import { useState as useState5, useEffect as useEffect3, useMemo as useMemo5 } from "react";
1336
1378
  import { Outlet, useNavigate, useLocation } from "react-router-dom";
1337
1379
  import { Fragment as Fragment4, jsx as jsx14, jsxs as jsxs10 } from "react/jsx-runtime";
1338
1380
  var EMPTY_PAGE_ID_MAPPING = {};
@@ -1367,48 +1409,31 @@ function PaceAppLayout({
1367
1409
  onRouteAccessDenied,
1368
1410
  onRouteStrictModeViolation
1369
1411
  }) {
1370
- const { user, signOut, updatePassword } = useUnifiedAuth();
1412
+ const { user, signOut, updatePassword, supabase } = useUnifiedAuth();
1413
+ const { selectedOrganisation } = useOrganisations();
1371
1414
  const navigate = useNavigate();
1372
1415
  const location = useLocation();
1373
- const checkPermission = useCallback3(async (permission, pageId) => {
1374
- try {
1375
- if (!user?.id) return false;
1376
- const scope = {
1377
- organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
1378
- eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
1379
- appId: user.user_metadata?.appId || user.app_metadata?.appId
1416
+ let selectedEvent = null;
1417
+ try {
1418
+ const eventsContext = useEvents();
1419
+ selectedEvent = eventsContext.selectedEvent;
1420
+ } catch (error) {
1421
+ }
1422
+ const { resolvedScope } = useResolvedScope({
1423
+ supabase: supabase || null,
1424
+ selectedOrganisationId: selectedOrganisation?.id || null,
1425
+ selectedEventId: selectedEvent?.event_id || null
1426
+ });
1427
+ const scope = useMemo5(() => {
1428
+ if (!resolvedScope?.organisationId) {
1429
+ return {
1430
+ organisationId: selectedOrganisation?.id || "",
1431
+ eventId: selectedEvent?.event_id || void 0,
1432
+ appId: void 0
1380
1433
  };
1381
- try {
1382
- const { isSuperAdmin: isSuperAdmin2 } = await import("./api-5I3E47G2.js");
1383
- const isSuper = await isSuperAdmin2(user.id);
1384
- if (isSuper) {
1385
- return true;
1386
- }
1387
- } catch (error) {
1388
- if (error && typeof error === "object" && "code" in error && error.code === "RBAC_NOT_INITIALIZED") {
1389
- } else {
1390
- throw error;
1391
- }
1392
- }
1393
- if (!scope.organisationId) {
1394
- console.warn("No organisation context available for permission check, denying access");
1395
- return false;
1396
- }
1397
- const fullPermission = permission.includes(":") ? permission : pageId ? `${permission}:page.${pageId}` : permission;
1398
- return await isPermitted({
1399
- userId: user.id,
1400
- scope,
1401
- permission: fullPermission,
1402
- pageId
1403
- });
1404
- } catch (error) {
1405
- console.error("Permission check failed:", error);
1406
- throw error;
1407
1434
  }
1408
- }, [user?.id]);
1409
- const [hasPermission, setHasPermission] = useState5(null);
1410
- const [isCheckingPermission, setIsCheckingPermission] = useState5(false);
1411
- const [permissionError, setPermissionError] = useState5(null);
1435
+ return resolvedScope;
1436
+ }, [resolvedScope, selectedOrganisation?.id, selectedEvent?.event_id]);
1412
1437
  const defaultNavItems = useMemo5(() => [
1413
1438
  { id: "home", label: "Home", href: "/", icon: "Home" },
1414
1439
  { id: "dashboard", label: "Dashboard", href: "/dashboard", icon: "LayoutDashboard" },
@@ -1425,60 +1450,54 @@ function PaceAppLayout({
1425
1450
  const currentPath = location.pathname;
1426
1451
  return pageIdMapping[currentPath] || currentPath.slice(1) || "home";
1427
1452
  }, [location.pathname, pageIdMapping]);
1453
+ const currentPermission = useMemo5(() => {
1454
+ if (!enforcePermissions) {
1455
+ return "read:page.home";
1456
+ }
1457
+ const permissionString = `${currentRoutePermission}:page.${currentPageId}`;
1458
+ return permissionString;
1459
+ }, [enforcePermissions, currentRoutePermission, currentPageId]);
1460
+ const { can, isLoading: isCheckingPermission, error: permissionError } = useCan(
1461
+ user?.id || "",
1462
+ scope,
1463
+ currentPermission,
1464
+ currentPageId,
1465
+ true
1466
+ // useCache
1467
+ );
1468
+ const hasPermission = enforcePermissions ? can : true;
1428
1469
  useEffect3(() => {
1429
1470
  if (!enforcePermissions) {
1430
- setHasPermission(true);
1431
1471
  return;
1432
1472
  }
1433
- let isMounted = true;
1434
- const checkRoutePermission = async () => {
1435
- if (!isMounted) return;
1436
- setIsCheckingPermission(true);
1437
- setPermissionError(null);
1438
- try {
1439
- const hasAccess = await checkPermission(currentRoutePermission, currentPageId);
1440
- if (!isMounted) return;
1441
- setHasPermission(hasAccess);
1442
- if (auditLog) {
1443
- console.log(`[PaceAppLayout] Page access attempt:`, {
1444
- pageName: currentPageId,
1445
- operation: currentRoutePermission,
1446
- userId: user?.id,
1447
- allowed: hasAccess,
1448
- strictMode,
1449
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1450
- });
1451
- }
1452
- if (strictMode && !hasAccess) {
1453
- console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
1454
- pageName: currentPageId,
1455
- operation: currentRoutePermission,
1456
- userId: user?.id,
1457
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
1458
- });
1459
- if (onStrictModeViolation) {
1460
- onStrictModeViolation(currentPageId, currentRoutePermission);
1461
- }
1462
- }
1463
- if (!hasAccess && onPageAccessDenied) {
1464
- onPageAccessDenied(currentPageId, currentRoutePermission);
1465
- }
1466
- } catch (error) {
1467
- if (!isMounted) return;
1468
- console.error(`[PaceAppLayout] Permission check failed for ${currentPageId}:`, error);
1469
- setPermissionError(error instanceof Error ? error : new Error("Permission check failed"));
1470
- setHasPermission(false);
1471
- } finally {
1472
- if (isMounted) {
1473
- setIsCheckingPermission(false);
1474
- }
1473
+ if (isCheckingPermission) {
1474
+ return;
1475
+ }
1476
+ if (auditLog) {
1477
+ console.log(`[PaceAppLayout] Page access attempt:`, {
1478
+ pageName: currentPageId,
1479
+ operation: currentRoutePermission,
1480
+ userId: user?.id,
1481
+ allowed: can,
1482
+ strictMode,
1483
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1484
+ });
1485
+ }
1486
+ if (strictMode && !can) {
1487
+ console.error(`[PaceAppLayout] STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
1488
+ pageName: currentPageId,
1489
+ operation: currentRoutePermission,
1490
+ userId: user?.id,
1491
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
1492
+ });
1493
+ if (onStrictModeViolation) {
1494
+ onStrictModeViolation(currentPageId, currentRoutePermission);
1475
1495
  }
1476
- };
1477
- checkRoutePermission();
1478
- return () => {
1479
- isMounted = false;
1480
- };
1481
- }, [enforcePermissions, currentRoutePermission, currentPageId, strictMode, user?.id]);
1496
+ }
1497
+ if (!can && onPageAccessDenied) {
1498
+ onPageAccessDenied(currentPageId, currentRoutePermission);
1499
+ }
1500
+ }, [enforcePermissions, can, isCheckingPermission, currentPageId, currentRoutePermission, user?.id, strictMode, auditLog, onPageAccessDenied, onStrictModeViolation]);
1482
1501
  const [filteredMenuItems, setFilteredMenuItems] = useState5(baseMenuItems);
1483
1502
  useEffect3(() => {
1484
1503
  if (!filterNavigationByPermissions) {
@@ -1493,13 +1512,13 @@ function PaceAppLayout({
1493
1512
  }
1494
1513
  return;
1495
1514
  }
1496
- const scope = {
1515
+ const scope2 = {
1497
1516
  organisationId: user.user_metadata?.organisationId || user.app_metadata?.organisationId,
1498
1517
  eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,
1499
1518
  appId: user.user_metadata?.appId || user.app_metadata?.appId
1500
1519
  };
1501
1520
  try {
1502
- const { isSuperAdmin: isSuperAdmin2 } = await import("./api-5I3E47G2.js");
1521
+ const { isSuperAdmin: isSuperAdmin2 } = await import("./api-SIZPFBFX.js");
1503
1522
  const isSuper = await isSuperAdmin2(user.id);
1504
1523
  if (isSuper) {
1505
1524
  if (isMounted) {
@@ -1513,17 +1532,17 @@ function PaceAppLayout({
1513
1532
  throw error;
1514
1533
  }
1515
1534
  }
1516
- if (!scope.organisationId) {
1535
+ if (!scope2.organisationId) {
1517
1536
  if (isMounted) {
1518
1537
  setFilteredMenuItems(baseMenuItems);
1519
1538
  }
1520
1539
  return;
1521
1540
  }
1522
1541
  try {
1523
- const { getPermissionMap } = await import("./api-5I3E47G2.js");
1542
+ const { getPermissionMap } = await import("./api-SIZPFBFX.js");
1524
1543
  const permissionMap = await getPermissionMap({
1525
1544
  userId: user.id,
1526
- scope
1545
+ scope: scope2
1527
1546
  });
1528
1547
  const filtered = baseMenuItems.map((item) => {
1529
1548
  if (!item.href) return { item, hasAccess: true };
@@ -1556,7 +1575,7 @@ function PaceAppLayout({
1556
1575
  return () => {
1557
1576
  isMounted = false;
1558
1577
  };
1559
- }, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, checkPermission, user?.id, user?.user_metadata, user?.app_metadata]);
1578
+ }, [baseMenuItems, filterNavigationByPermissions, pageIdMapping, routePermissions, defaultPermission, can, user?.id, user?.user_metadata, user?.app_metadata]);
1560
1579
  useEffect3(() => {
1561
1580
  if (!roleBasedRouting || routeConfig.length === 0) return;
1562
1581
  let isMounted = true;
@@ -1579,7 +1598,13 @@ function PaceAppLayout({
1579
1598
  let hasAccess = true;
1580
1599
  if (currentRoute.pageId && currentRoute.permissions && currentRoute.permissions.length > 0) {
1581
1600
  try {
1582
- const hasPagePermission = await checkPermission(currentRoute.permissions[0], currentRoute.pageId);
1601
+ const { isPermittedCached } = await import("./api-SIZPFBFX.js");
1602
+ const hasPagePermission = await isPermittedCached({
1603
+ userId: user?.id || "",
1604
+ scope,
1605
+ permission: currentRoute.permissions[0],
1606
+ pageId: currentRoute.pageId
1607
+ });
1583
1608
  if (!isMounted) return;
1584
1609
  hasAccess = hasPagePermission;
1585
1610
  } catch (error) {
@@ -1589,7 +1614,7 @@ function PaceAppLayout({
1589
1614
  }
1590
1615
  }
1591
1616
  if (hasAccess && currentRoute.roles && currentRoute.roles.length > 0 && user?.id) {
1592
- const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-A7I23UCN.js");
1617
+ const { useUnifiedAuth: useUnifiedAuth2 } = await import("./UnifiedAuthProvider-LUM3QLS5.js");
1593
1618
  hasAccess = true;
1594
1619
  }
1595
1620
  if (!isMounted) return;
@@ -1629,7 +1654,7 @@ function PaceAppLayout({
1629
1654
  return () => {
1630
1655
  isMounted = false;
1631
1656
  };
1632
- }, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, checkPermission, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
1657
+ }, [roleBasedRouting, routeConfig, location.pathname, strictMode, user?.id, fallbackRoute, scope, navigate, auditLog, onRouteAccessDenied, onRouteStrictModeViolation]);
1633
1658
  const handleSignOut = async () => {
1634
1659
  await signOut();
1635
1660
  };
@@ -1697,9 +1722,10 @@ function PaceAppLayout({
1697
1722
  }
1698
1723
 
1699
1724
  // src/components/PaceLoginPage/PaceLoginPage.tsx
1700
- import { useEffect as useEffect4, useState as useState6 } from "react";
1725
+ import { useEffect as useEffect4, useState as useState6, useContext } from "react";
1701
1726
  import { useNavigate as useNavigate2 } from "react-router-dom";
1702
1727
  init_runtime();
1728
+ init_EventServiceProvider();
1703
1729
  import { jsx as jsx15, jsxs as jsxs11 } from "react/jsx-runtime";
1704
1730
  var PaceLoginPage = ({
1705
1731
  appName = "Pace",
@@ -1711,9 +1737,27 @@ var PaceLoginPage = ({
1711
1737
  const [isSigningIn, setIsSigningIn] = useState6(false);
1712
1738
  const [accessError, setAccessError] = useState6(null);
1713
1739
  const [isCheckingAccess, setIsCheckingAccess] = useState6(false);
1740
+ const eventServiceContext = useContext(EventServiceContext);
1741
+ const eventService = eventServiceContext?.eventService || null;
1714
1742
  useEffect4(() => {
1715
1743
  clearPalette();
1716
1744
  }, []);
1745
+ useEffect4(() => {
1746
+ const restoreEvent = async () => {
1747
+ try {
1748
+ const isOnLoginPage = window.location.pathname === "/login" || window.location.pathname.startsWith("/login");
1749
+ if (isOnLoginPage && eventService) {
1750
+ await eventService.restorePersistedEvent();
1751
+ }
1752
+ } catch (error) {
1753
+ console.debug("[PaceLoginPage] Could not restore persisted event (service may not be ready):", error);
1754
+ }
1755
+ };
1756
+ const timeoutId = setTimeout(() => {
1757
+ restoreEvent();
1758
+ }, 100);
1759
+ return () => clearTimeout(timeoutId);
1760
+ }, [eventService]);
1717
1761
  useEffect4(() => {
1718
1762
  if (!requireAppAccess || !isAuthenticated || isLoading || !user || !supabase) {
1719
1763
  return;
@@ -2950,13 +2994,6 @@ function FileUpload({
2950
2994
  };
2951
2995
  onProgress?.(finalProgress);
2952
2996
  onUploadSuccess?.(result);
2953
- setTimeout(() => {
2954
- setUploadStates((prev) => {
2955
- const updated = new Map(prev);
2956
- updated.delete(fileId);
2957
- return updated;
2958
- });
2959
- }, 3e3);
2960
2997
  } else {
2961
2998
  setUploadStates((prev) => {
2962
2999
  const updated = new Map(prev);
@@ -3151,7 +3188,7 @@ function FileUpload({
3151
3188
  }
3152
3189
 
3153
3190
  // src/components/FileDisplay/FileDisplay.tsx
3154
- import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useContext, useMemo as useMemo9 } from "react";
3191
+ import { useState as useState12, useEffect as useEffect8, useRef as useRef5, useContext as useContext2, useMemo as useMemo9 } from "react";
3155
3192
 
3156
3193
  // src/hooks/useFileUrl.ts
3157
3194
  import { useState as useState11, useEffect as useEffect7, useCallback as useCallback7, useRef as useRef4 } from "react";
@@ -3531,7 +3568,7 @@ function FileDisplayPublic({
3531
3568
  fallbackText,
3532
3569
  fallbackSize
3533
3570
  }) {
3534
- const publicPageContext = useContext(PublicPageContext);
3571
+ const publicPageContext = useContext2(PublicPageContext);
3535
3572
  const supabase = publicPageContext?.supabase ?? null;
3536
3573
  if (!supabase) {
3537
3574
  return /* @__PURE__ */ jsx22("div", { className: `text-sec-500 text-center p-4 ${className}`, children: "Supabase client not available in public context" });
@@ -4413,4 +4450,4 @@ export {
4413
4450
  PublicPageDiagnostic,
4414
4451
  PublicPageContextChecker
4415
4452
  };
4416
- //# sourceMappingURL=chunk-P72NKAT5.js.map
4453
+ //# sourceMappingURL=chunk-2BIDKXQU.js.map