@jmruthers/pace-core 0.5.193 → 0.6.2

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 (577) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +299 -0
  4. package/cursor-rules/01-standards-compliance.mdc +244 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +222 -0
  7. package/cursor-rules/04-testing-standards.mdc +268 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +309 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +214 -0
  11. package/cursor-rules/08-markup-quality.mdc +452 -0
  12. package/cursor-rules/CHANGELOG.md +119 -0
  13. package/cursor-rules/README.md +192 -0
  14. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  15. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-BMRU8a1j.d.ts} +34 -2
  16. package/dist/{DataTable-5FU7IESH.js → DataTable-TPTKCX4D.js} +10 -9
  17. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +385 -261
  18. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  19. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  20. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  21. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  22. package/dist/chunk-24UVZUZG.js.map +1 -0
  23. package/dist/{chunk-HWIIPPNI.js → chunk-2UOI2FG5.js} +20 -20
  24. package/dist/chunk-2UOI2FG5.js.map +1 -0
  25. package/dist/{chunk-E3SPN4VZ 5.js → chunk-3XC4CPTD.js} +4345 -3986
  26. package/dist/chunk-3XC4CPTD.js.map +1 -0
  27. package/dist/{chunk-7EQTDTTJ.js → chunk-6J4GEEJR.js} +172 -45
  28. package/dist/chunk-6J4GEEJR.js.map +1 -0
  29. package/dist/{chunk-6C4YBBJM 5.js → chunk-6SOIHG6Z.js} +1 -1
  30. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  31. package/dist/{chunk-7FLMSG37.js → chunk-EHMR7VYL.js} +25 -25
  32. package/dist/chunk-EHMR7VYL.js.map +1 -0
  33. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  34. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  35. package/dist/{chunk-QWWZ5CAQ.js → chunk-FFQEQTNW.js} +7 -9
  36. package/dist/chunk-FFQEQTNW.js.map +1 -0
  37. package/dist/chunk-FMUCXFII.js +76 -0
  38. package/dist/chunk-FMUCXFII.js.map +1 -0
  39. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  40. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  41. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  42. package/dist/chunk-L4OXEN46.js.map +1 -0
  43. package/dist/{chunk-R77UEZ4E 3.js → chunk-M43Y4SSO.js} +1 -1
  44. package/dist/chunk-M43Y4SSO.js.map +1 -0
  45. package/dist/{chunk-IIELH4DL.js → chunk-MMZ7JXPU.js} +60 -223
  46. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  47. package/dist/{chunk-NOAYCWCX 5.js → chunk-NECFR5MM.js} +394 -312
  48. package/dist/chunk-NECFR5MM.js.map +1 -0
  49. package/dist/{chunk-BC4IJKSL.js → chunk-SFZUDBL5.js} +40 -4
  50. package/dist/chunk-SFZUDBL5.js.map +1 -0
  51. package/dist/{chunk-XNXXZ43G.js → chunk-XWQCNGTQ.js} +748 -364
  52. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  53. package/dist/components.d.ts +6 -6
  54. package/dist/components.js +15 -12
  55. package/dist/components.js.map +1 -1
  56. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  57. package/dist/hooks.d.ts +59 -126
  58. package/dist/hooks.js +19 -28
  59. package/dist/hooks.js.map +1 -1
  60. package/dist/index.d.ts +63 -16
  61. package/dist/index.js +23 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/providers.d.ts +21 -3
  64. package/dist/providers.js +2 -2
  65. package/dist/rbac/index.d.ts +146 -115
  66. package/dist/rbac/index.js +8 -11
  67. package/dist/theming/runtime.d.ts +1 -13
  68. package/dist/theming/runtime.js +1 -1
  69. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  70. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  71. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  72. package/dist/types.d.ts +2 -2
  73. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +34 -4
  74. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  75. package/dist/utils.d.ts +4 -5
  76. package/dist/utils.js +15 -15
  77. package/dist/utils.js.map +1 -1
  78. package/docs/api/README.md +7 -1
  79. package/docs/api/classes/ColumnFactory.md +8 -8
  80. package/docs/api/classes/InvalidScopeError.md +4 -4
  81. package/docs/api/classes/Logger.md +1 -1
  82. package/docs/api/classes/MissingUserContextError.md +4 -4
  83. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  84. package/docs/api/classes/PermissionDeniedError.md +4 -4
  85. package/docs/api/classes/RBACAuditManager.md +1 -1
  86. package/docs/api/classes/RBACCache.md +1 -1
  87. package/docs/api/classes/RBACEngine.md +1 -1
  88. package/docs/api/classes/RBACError.md +4 -4
  89. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  90. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  91. package/docs/api/classes/StorageUtils.md +1 -1
  92. package/docs/api/enums/FileCategory.md +1 -1
  93. package/docs/api/enums/LogLevel.md +1 -1
  94. package/docs/api/enums/RBACErrorCode.md +1 -1
  95. package/docs/api/enums/RPCFunction.md +1 -1
  96. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  97. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  98. package/docs/api/interfaces/AggregateConfig.md +4 -4
  99. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  100. package/docs/api/interfaces/AvatarProps.md +1 -1
  101. package/docs/api/interfaces/BadgeProps.md +9 -2
  102. package/docs/api/interfaces/ButtonProps.md +7 -4
  103. package/docs/api/interfaces/CalendarProps.md +8 -5
  104. package/docs/api/interfaces/CardProps.md +8 -5
  105. package/docs/api/interfaces/ColorPalette.md +1 -1
  106. package/docs/api/interfaces/ColorShade.md +1 -1
  107. package/docs/api/interfaces/ComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  109. package/docs/api/interfaces/DataRecord.md +1 -1
  110. package/docs/api/interfaces/DataTableAction.md +24 -21
  111. package/docs/api/interfaces/DataTableColumn.md +31 -31
  112. package/docs/api/interfaces/DataTableProps.md +1 -1
  113. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  114. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  115. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  116. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  117. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  118. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  119. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  120. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  121. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  122. package/docs/api/interfaces/ExportColumn.md +1 -1
  123. package/docs/api/interfaces/ExportOptions.md +8 -8
  124. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  125. package/docs/api/interfaces/FileMetadata.md +1 -1
  126. package/docs/api/interfaces/FileReference.md +1 -1
  127. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  128. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  129. package/docs/api/interfaces/FileUploadProps.md +26 -23
  130. package/docs/api/interfaces/FooterProps.md +10 -8
  131. package/docs/api/interfaces/FormFieldProps.md +10 -10
  132. package/docs/api/interfaces/FormProps.md +1 -1
  133. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  134. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  135. package/docs/api/interfaces/InputProps.md +7 -4
  136. package/docs/api/interfaces/LabelProps.md +1 -1
  137. package/docs/api/interfaces/LoggerConfig.md +1 -1
  138. package/docs/api/interfaces/LoginFormProps.md +14 -11
  139. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  140. package/docs/api/interfaces/NavigationContextType.md +1 -1
  141. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  142. package/docs/api/interfaces/NavigationItem.md +11 -11
  143. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  144. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  145. package/docs/api/interfaces/Organisation.md +1 -1
  146. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  147. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  148. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  149. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  150. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  151. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  152. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  153. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  154. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  155. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  156. package/docs/api/interfaces/PaletteData.md +1 -1
  157. package/docs/api/interfaces/ParsedAddress.md +1 -1
  158. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  159. package/docs/api/interfaces/ProgressProps.md +1 -1
  160. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  161. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  162. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  163. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  164. package/docs/api/interfaces/QuickFix.md +1 -1
  165. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  166. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  167. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  168. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  169. package/docs/api/interfaces/RBACConfig.md +1 -1
  170. package/docs/api/interfaces/RBACContext.md +1 -1
  171. package/docs/api/interfaces/RBACLogger.md +1 -1
  172. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  173. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  174. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  175. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  176. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  177. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  178. package/docs/api/interfaces/RBACResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  181. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  182. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  183. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  184. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  185. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  186. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  187. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  188. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  189. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  190. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  191. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  192. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  193. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  194. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  195. package/docs/api/interfaces/RouteConfig.md +1 -1
  196. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  197. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  198. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  199. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  200. package/docs/api/interfaces/SetupIssue.md +1 -1
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +3 -3
  215. package/docs/api/interfaces/TextareaProps.md +1 -1
  216. package/docs/api/interfaces/ToastActionElement.md +4 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  220. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  221. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  222. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  223. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  224. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  225. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  226. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  227. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  228. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  229. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  230. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  231. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  232. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  233. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  234. package/docs/api/interfaces/UserEventAccess.md +14 -11
  235. package/docs/api/interfaces/UserMenuProps.md +8 -6
  236. package/docs/api/interfaces/UserProfile.md +1 -1
  237. package/docs/api/modules.md +575 -634
  238. package/docs/architecture/database-schema-requirements.md +161 -0
  239. package/docs/core-concepts/rbac-system.md +3 -3
  240. package/docs/documentation-index.md +2 -4
  241. package/docs/getting-started/cursor-rules.md +263 -0
  242. package/docs/getting-started/installation-guide.md +6 -1
  243. package/docs/getting-started/quick-start.md +6 -1
  244. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  245. package/docs/migration/MIGRATION_GUIDE.md +6 -28
  246. package/docs/migration/README.md +52 -6
  247. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  248. package/docs/migration/V0.6.0_REACT_19_MIGRATION.md +227 -0
  249. package/docs/migration/database-changes-december-2025.md +3 -3
  250. package/docs/rbac/event-based-apps.md +1 -1
  251. package/docs/rbac/getting-started.md +1 -1
  252. package/docs/rbac/quick-start.md +1 -1
  253. package/docs/standards/README.md +40 -0
  254. package/docs/troubleshooting/migration.md +4 -4
  255. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  256. package/package.json +12 -6
  257. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  258. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  259. package/scripts/audit/core/checks/bundle.cjs +142 -0
  260. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +737 -691
  261. package/scripts/audit/core/checks/config.cjs +54 -0
  262. package/scripts/audit/core/checks/coverage.cjs +84 -0
  263. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  264. package/scripts/audit/core/checks/documentation.cjs +203 -0
  265. package/scripts/audit/core/checks/environment.cjs +128 -0
  266. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  267. package/scripts/audit/core/checks/forms.cjs +172 -0
  268. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  269. package/scripts/audit/core/checks/hooks.cjs +334 -0
  270. package/scripts/audit/core/checks/imports.cjs +244 -0
  271. package/scripts/audit/core/checks/performance.cjs +325 -0
  272. package/scripts/audit/core/checks/routes.cjs +117 -0
  273. package/scripts/audit/core/checks/state.cjs +130 -0
  274. package/scripts/audit/core/checks/structure.cjs +65 -0
  275. package/scripts/audit/core/checks/style.cjs +584 -0
  276. package/scripts/audit/core/checks/testing.cjs +122 -0
  277. package/scripts/audit/core/checks/typescript.cjs +61 -0
  278. package/scripts/audit/core/scanner.cjs +199 -0
  279. package/scripts/audit/core/utils.cjs +137 -0
  280. package/scripts/audit/index.cjs +223 -0
  281. package/scripts/audit/reporters/console.cjs +151 -0
  282. package/scripts/audit/reporters/json.cjs +54 -0
  283. package/scripts/audit/reporters/markdown.cjs +124 -0
  284. package/scripts/audit-consuming-app.cjs +86 -0
  285. package/scripts/build-docs/build-decision.js +240 -0
  286. package/scripts/build-docs/cache-utils.js +105 -0
  287. package/scripts/build-docs/content-normalization.js +150 -0
  288. package/scripts/build-docs/file-utils.js +105 -0
  289. package/scripts/build-docs/git-utils.js +86 -0
  290. package/scripts/build-docs/hash-utils.js +116 -0
  291. package/scripts/build-docs/typedoc-runner.js +220 -0
  292. package/scripts/build-docs-incremental.js +77 -913
  293. package/scripts/install-cursor-rules.cjs +236 -0
  294. package/scripts/utils/command-runner.js +16 -11
  295. package/scripts/validate-formats.js +61 -56
  296. package/scripts/validate-master.js +74 -69
  297. package/scripts/validate-pre-publish.js +70 -65
  298. package/src/__tests__/helpers/test-providers.tsx +1 -1
  299. package/src/__tests__/helpers/test-utils.tsx +1 -1
  300. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  301. package/src/components/Alert/Alert.test.tsx +12 -18
  302. package/src/components/Alert/Alert.tsx +5 -7
  303. package/src/components/Avatar/Avatar.test.tsx +4 -4
  304. package/src/components/Badge/Badge.tsx +16 -4
  305. package/src/components/Button/Button.tsx +27 -4
  306. package/src/components/Calendar/Calendar.tsx +9 -3
  307. package/src/components/Card/Card.tsx +4 -0
  308. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  309. package/src/components/Checkbox/Checkbox.tsx +2 -2
  310. package/src/components/DataTable/DataTable.test.tsx +57 -93
  311. package/src/components/DataTable/DataTable.tsx +40 -6
  312. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  313. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +29 -7
  314. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  315. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  316. package/src/components/DataTable/components/AccessDeniedPage.tsx +17 -26
  317. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  318. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  319. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  320. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  321. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  322. package/src/components/DataTable/components/DataTableCore.tsx +200 -561
  323. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  324. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  325. package/src/components/DataTable/components/DataTableModals.tsx +9 -1
  326. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  327. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  328. package/src/components/DataTable/components/EditFields.tsx +307 -0
  329. package/src/components/DataTable/components/EditableRow.tsx +9 -1
  330. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  331. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  332. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  333. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  334. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  335. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  336. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  337. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  338. package/src/components/DataTable/components/UnifiedTableBody.tsx +62 -852
  339. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  340. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  341. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  342. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  343. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  344. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  345. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  346. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  347. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  348. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  349. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  350. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  351. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  352. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  353. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  354. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  355. package/src/components/DataTable/hooks/useColumnReordering.ts +14 -2
  356. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  357. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  358. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  359. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  360. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  361. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  362. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  363. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  364. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  365. package/src/components/DataTable/styles.ts +6 -6
  366. package/src/components/DataTable/types.ts +6 -10
  367. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  368. package/src/components/DataTable/utils/debugTools.ts +18 -113
  369. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  370. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  371. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  372. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  373. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  374. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  375. package/src/components/Dialog/Dialog.tsx +8 -7
  376. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  377. package/src/components/ErrorBoundary/ErrorBoundary.tsx +46 -6
  378. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  379. package/src/components/ErrorBoundary/index.ts +27 -2
  380. package/src/components/EventSelector/EventSelector.tsx +4 -1
  381. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  382. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  383. package/src/components/FileUpload/FileUpload.tsx +22 -2
  384. package/src/components/Footer/Footer.test.tsx +16 -16
  385. package/src/components/Footer/Footer.tsx +15 -12
  386. package/src/components/Form/Form.test.tsx +36 -15
  387. package/src/components/Form/Form.tsx +31 -26
  388. package/src/components/Header/Header.tsx +22 -11
  389. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  390. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  391. package/src/components/Input/Input.test.tsx +2 -2
  392. package/src/components/Input/Input.tsx +36 -34
  393. package/src/components/Label/Label.tsx +1 -1
  394. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  395. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  396. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  397. package/src/components/LoginForm/LoginForm.tsx +12 -8
  398. package/src/components/NavigationMenu/NavigationMenu.tsx +15 -514
  399. package/src/components/NavigationMenu/types.ts +56 -0
  400. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  401. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  402. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  403. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +54 -52
  404. package/src/components/PaceAppLayout/PaceAppLayout.tsx +33 -12
  405. package/src/components/PaceAppLayout/README.md +1 -1
  406. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  407. package/src/components/PaceLoginPage/PaceLoginPage.tsx +4 -1
  408. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  409. package/src/components/PasswordChange/PasswordChangeForm.tsx +10 -1
  410. package/src/components/Progress/Progress.tsx +1 -1
  411. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  412. package/src/components/PublicLayout/PublicPageLayout.tsx +3 -6
  413. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  414. package/src/components/Select/Select.tsx +95 -438
  415. package/src/components/Select/context.ts +23 -0
  416. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  417. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  418. package/src/components/Select/hooks/useSelectState.ts +104 -0
  419. package/src/components/Select/index.ts +9 -1
  420. package/src/components/Select/types.ts +123 -0
  421. package/src/components/Select/utils/text.ts +26 -0
  422. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +5 -6
  423. package/src/components/Switch/Switch.tsx +4 -4
  424. package/src/components/Table/Table.tsx +1 -1
  425. package/src/components/Tabs/Tabs.tsx +1 -1
  426. package/src/components/Textarea/Textarea.tsx +27 -29
  427. package/src/components/Toast/Toast.tsx +5 -1
  428. package/src/components/Tooltip/Tooltip.tsx +3 -3
  429. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  430. package/src/components/UserMenu/UserMenu.tsx +22 -19
  431. package/src/components/index.ts +2 -2
  432. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  433. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  434. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  435. package/src/hooks/index.ts +1 -2
  436. package/src/hooks/public/usePublicEvent.ts +5 -1
  437. package/src/hooks/public/usePublicEventLogo.ts +5 -1
  438. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  439. package/src/hooks/public/usePublicRouteParams.ts +5 -1
  440. package/src/hooks/services/useAuth.ts +32 -0
  441. package/src/hooks/services/useCurrentEvent.ts +6 -0
  442. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  443. package/src/hooks/useDataTableState.ts +8 -18
  444. package/src/hooks/useDebounce.ts +9 -0
  445. package/src/hooks/useEventTheme.ts +6 -0
  446. package/src/hooks/useFileDisplay.ts +4 -0
  447. package/src/hooks/useFileReference.ts +25 -7
  448. package/src/hooks/useFileUrl.ts +11 -1
  449. package/src/hooks/useFocusManagement.ts +16 -2
  450. package/src/hooks/useFocusTrap.ts +7 -4
  451. package/src/hooks/useFormDialog.ts +8 -7
  452. package/src/hooks/useInactivityTracker.ts +4 -1
  453. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  454. package/src/hooks/useOrganisationPermissions.ts +4 -0
  455. package/src/hooks/useOrganisationSecurity.ts +4 -0
  456. package/src/hooks/usePerformanceMonitor.ts +4 -0
  457. package/src/hooks/usePermissionCache.ts +8 -1
  458. package/src/hooks/useQueryCache.ts +12 -1
  459. package/src/hooks/useSessionRestoration.ts +4 -0
  460. package/src/hooks/useStorage.ts +4 -0
  461. package/src/hooks/useToast.ts +3 -3
  462. package/src/index.ts +2 -1
  463. package/src/providers/__tests__/OrganisationProvider.test.tsx +115 -49
  464. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  465. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  466. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  467. package/src/providers/services/EventServiceProvider.tsx +18 -0
  468. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  469. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  470. package/src/providers/services/UnifiedAuthProvider.tsx +58 -22
  471. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +33 -7
  472. package/src/rbac/README.md +1 -1
  473. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +26 -26
  474. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  475. package/src/rbac/adapters.tsx +14 -5
  476. package/src/rbac/api.ts +100 -67
  477. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  478. package/src/rbac/components/NavigationGuard.tsx +1 -1
  479. package/src/rbac/components/NavigationProvider.tsx +5 -2
  480. package/src/rbac/components/PagePermissionGuard.tsx +158 -18
  481. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  482. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  483. package/src/rbac/components/RoleBasedRouter.tsx +6 -2
  484. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  485. package/src/rbac/components/SecureDataProvider.tsx +21 -6
  486. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  487. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  488. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  489. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  490. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  491. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  492. package/src/rbac/engine.ts +38 -14
  493. package/src/rbac/hooks/permissions/index.ts +7 -0
  494. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  495. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  496. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  497. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  498. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  499. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  500. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  501. package/src/rbac/hooks/useCan.test.ts +71 -64
  502. package/src/rbac/hooks/usePermissions.ts +14 -995
  503. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  504. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  505. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  506. package/src/rbac/permissions.ts +0 -30
  507. package/src/rbac/secureClient.ts +212 -61
  508. package/src/rbac/types.ts +8 -0
  509. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  510. package/src/theming/parseEventColours.ts +5 -19
  511. package/src/types/vitest-globals.d.ts +51 -26
  512. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  513. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  514. package/src/utils/__tests__/index.unit.test.ts +2 -2
  515. package/src/utils/audit/audit.ts +0 -3
  516. package/src/utils/core/cn.ts +1 -1
  517. package/src/utils/file-reference/index.ts +53 -1
  518. package/src/utils/formatting/formatting.ts +8 -18
  519. package/src/utils/index.ts +0 -1
  520. package/src/utils/security/secureDataAccess.test.ts +31 -20
  521. package/src/utils/security/secureDataAccess.ts +4 -3
  522. package/dist/chunk-6C4YBBJM.js +0 -628
  523. package/dist/chunk-6C4YBBJM.js.map +0 -1
  524. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  525. package/dist/chunk-7EQTDTTJ.js 2.map +0 -1
  526. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  527. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  528. package/dist/chunk-7FLMSG37.js.map +0 -1
  529. package/dist/chunk-BC4IJKSL.js.map +0 -1
  530. package/dist/chunk-E3SPN4VZ.js +0 -12917
  531. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  532. package/dist/chunk-E66EQZE6 5.js +0 -37
  533. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  534. package/dist/chunk-HWIIPPNI.js.map +0 -1
  535. package/dist/chunk-I7PSE6JW 5.js +0 -191
  536. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  537. package/dist/chunk-I7PSE6JW.js.map +0 -1
  538. package/dist/chunk-IIELH4DL.js.map +0 -1
  539. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  540. package/dist/chunk-KNC55RTG.js.map +0 -1
  541. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  542. package/dist/chunk-LFNCN2SP.js +0 -412
  543. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  544. package/dist/chunk-LFNCN2SP.js.map +0 -1
  545. package/dist/chunk-LMC26NLJ 2.js +0 -84
  546. package/dist/chunk-NOAYCWCX.js +0 -4993
  547. package/dist/chunk-NOAYCWCX.js.map +0 -1
  548. package/dist/chunk-QWWZ5CAQ.js 3.map +0 -1
  549. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  550. package/dist/chunk-QXHPKYJV 3.js +0 -113
  551. package/dist/chunk-R77UEZ4E.js +0 -68
  552. package/dist/chunk-R77UEZ4E.js.map +0 -1
  553. package/dist/chunk-SQGMNID3.js.map +0 -1
  554. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  555. package/dist/chunk-XNXXZ43G.js.map +0 -1
  556. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  557. package/dist/components.js 5.map +0 -1
  558. package/dist/styles/index 2.js +0 -12
  559. package/dist/styles/index.js 5.map +0 -1
  560. package/dist/theming/runtime 5.js +0 -19
  561. package/dist/theming/runtime.js 5.map +0 -1
  562. package/docs/api/classes/ErrorBoundary.md +0 -144
  563. package/docs/migration/quick-migration-guide.md +0 -356
  564. package/docs/migration/service-architecture.md +0 -281
  565. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  566. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  567. package/src/hooks/useSecureDataAccess.ts +0 -666
  568. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  569. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  570. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  571. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  572. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  573. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  574. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  575. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  576. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  577. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -61,7 +61,7 @@
61
61
  * - Efficient error handling
62
62
  *
63
63
  * @dependencies
64
- * - React 18+ - Component framework
64
+ * - React 19+ - Component framework
65
65
  * - useCan hook - Permission checking
66
66
  * - useUnifiedAuth - Authentication context
67
67
  * - RBAC types - Type definitions
@@ -141,17 +141,86 @@ const PagePermissionGuardComponent = ({
141
141
  const { user, selectedOrganisation, selectedEvent, supabase, appId: contextAppId, appName } = useUnifiedAuth();
142
142
 
143
143
  const [hasChecked, setHasChecked] = useState(false);
144
+
145
+ // Determine the page ID for permission checking
146
+ const effectivePageId = useMemo((): string => {
147
+ return pageId || pageName;
148
+ }, [pageId, pageName]);
149
+
150
+ // Check super admin status directly - don't rely on useRBAC which might not be loaded yet
151
+ // This ensures super admins get immediate access without waiting for RBAC context to load
152
+ const [isSuperAdmin, setIsSuperAdmin] = useState<boolean | null>(null);
153
+
154
+ useEffect(() => {
155
+ if (!user?.id) {
156
+ setIsSuperAdmin(false);
157
+ return;
158
+ }
159
+
160
+ let cancelled = false;
161
+ const checkSuperAdmin = async () => {
162
+ const startTime = Date.now();
163
+ try {
164
+ const { isSuperAdmin: checkSuperAdmin } = await import('../api');
165
+
166
+ // Add timeout to prevent hanging
167
+ const timeoutPromise = new Promise<boolean>((_, reject) => {
168
+ setTimeout(() => reject(new Error('Super admin check timeout')), 10000);
169
+ });
170
+
171
+ const isSuper = await Promise.race([
172
+ checkSuperAdmin(user.id),
173
+ timeoutPromise
174
+ ]);
175
+
176
+ const elapsed = Date.now() - startTime;
177
+
178
+ if (!cancelled) {
179
+ setIsSuperAdmin(isSuper);
180
+ if (process.env.NODE_ENV === 'development') {
181
+ console.log('[PagePermissionGuard] Super admin check completed', {
182
+ userId: user.id,
183
+ isSuperAdmin: isSuper,
184
+ elapsedMs: elapsed
185
+ });
186
+ }
187
+ }
188
+ } catch (err) {
189
+ const elapsed = Date.now() - startTime;
190
+ if (!cancelled) {
191
+ console.error('[PagePermissionGuard] Error checking super admin', {
192
+ error: err,
193
+ userId: user.id,
194
+ elapsedMs: elapsed
195
+ });
196
+ // On timeout or error, assume not super admin (fail secure)
197
+ // But log it so we can debug
198
+ setIsSuperAdmin(false);
199
+ }
200
+ }
201
+ };
202
+
203
+ checkSuperAdmin();
204
+ return () => {
205
+ cancelled = true;
206
+ };
207
+ }, [user?.id]);
144
208
 
145
209
  // Use useResolvedScope hook for consistent scope resolution
146
210
  // For event-required apps: selectedOrganisation is null, org derived from event
147
211
  // For org-required apps: selectedOrganisation is available, event optional
148
212
  // For page-level permissions, PORTAL app allows both contexts to be optional
213
+ // NOTE: Super admins bypass scope requirements, but we still need to call the hook
149
214
  const { resolvedScope: hookResolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
150
215
  supabase,
151
216
  selectedOrganisationId: selectedOrganisation?.id || null,
152
217
  selectedEventId: selectedEvent?.event_id || null
153
218
  });
154
219
 
220
+ // For super admins, we can use a minimal scope since they bypass all checks
221
+ // This prevents scope resolution from blocking super admin access
222
+ const shouldBypassScopeForSuperAdmin = isSuperAdmin === true;
223
+
155
224
  // Use provided scope if available, otherwise use resolved scope
156
225
  // For PORTAL app page-level permissions, allow scope without org/event
157
226
  // Ensure appId is available for PORTAL/ADMIN (use contextAppId as fallback)
@@ -171,11 +240,6 @@ const PagePermissionGuardComponent = ({
171
240
  } : null)));
172
241
  const checkError = scopeError;
173
242
 
174
- // Determine the page ID for permission checking
175
- const effectivePageId = useMemo((): string => {
176
- return pageId || pageName;
177
- }, [pageId, pageName]);
178
-
179
243
  // Build the permission string
180
244
  const permission = useMemo((): Permission => {
181
245
  return `${operation}:page.${pageName}` as Permission;
@@ -225,22 +289,44 @@ const PagePermissionGuardComponent = ({
225
289
  return newScope;
226
290
  }, [effectiveScope, appName, contextAppId, selectedEvent?.event_id]);
227
291
 
292
+ // For super admins, use a minimal valid scope since they bypass all checks
293
+ // This prevents scope validation from blocking super admin access
294
+ const scopeForPermissionCheck = shouldBypassScopeForSuperAdmin && !stableScope?.organisationId
295
+ ? {
296
+ organisationId: undefined,
297
+ appId: contextAppId || undefined,
298
+ eventId: selectedEvent?.event_id || undefined
299
+ }
300
+ : stableScope;
301
+
302
+ // CRITICAL: If super admin is confirmed, skip useCan entirely to avoid any blocking
303
+ // Super admins have access to everything, so no need to check permissions
304
+ const shouldSkipPermissionCheck = isSuperAdmin === true;
305
+
228
306
  // Check if user has permission - only call useCan when we have a resolved scope with valid organisationId
229
307
  // If resolvedScope is null or has no organisationId, useCan will keep isLoading=true
230
308
  // Pass appName to useCan so it can be passed to isPermitted for PORTAL/ADMIN special case
309
+ // Pass precomputed super admin status to avoid duplicate checks in useCan
310
+ // For super admins, we can skip the check entirely, but still call useCan with a dummy scope to avoid hook rule violations
231
311
  const { can, isLoading: canIsLoading, error: canError } = useCan(
232
312
  user?.id || '',
233
- stableScope,
313
+ shouldSkipPermissionCheck ? { organisationId: undefined, appId: contextAppId || undefined, eventId: undefined } : scopeForPermissionCheck,
234
314
  permission,
235
315
  effectivePageId,
236
316
  true, // Use cache
317
+ isSuperAdmin, // precomputedSuperAdmin - null if checking, true/false if checked
237
318
  appName // Pass appName for PORTAL/ADMIN special case
238
319
  );
239
320
 
321
+ // Override can for super admins - they always have access
322
+ const effectiveCan = shouldSkipPermissionCheck ? true : can;
323
+ const effectiveIsLoading = shouldSkipPermissionCheck ? false : canIsLoading;
324
+
240
325
 
241
326
  // Combine loading states - we're loading if scope resolution or permission check is loading
242
327
  // For page-level permissions, PORTAL/ADMIN apps allow undefined organisationId
243
- const isLoading = scopeLoading || canIsLoading;
328
+ // Super admins bypass scope resolution - don't wait for it
329
+ const isLoading = shouldBypassScopeForSuperAdmin ? effectiveIsLoading : (scopeLoading || effectiveIsLoading);
244
330
  const error = checkError || canError;
245
331
 
246
332
  // Handle permission check completion
@@ -248,13 +334,13 @@ const PagePermissionGuardComponent = ({
248
334
  if (!isLoading && !error) {
249
335
  setHasChecked(true);
250
336
 
251
- if (!can && onDenied) {
337
+ if (!effectiveCan && onDenied) {
252
338
  onDenied(pageName, operation);
253
339
  }
254
340
  } else if (error) {
255
341
  setHasChecked(true);
256
342
  }
257
- }, [can, isLoading, error, pageName, operation, onDenied]);
343
+ }, [effectiveCan, isLoading, error, pageName, operation, onDenied]);
258
344
 
259
345
  // Log page access attempt for audit
260
346
  useEffect(() => {
@@ -265,16 +351,17 @@ const PagePermissionGuardComponent = ({
265
351
  operation,
266
352
  userId: user?.id,
267
353
  scope: effectiveScope,
268
- allowed: can,
354
+ allowed: effectiveCan,
355
+ isSuperAdmin,
269
356
  timestamp: new Date().toISOString()
270
357
  });
271
358
  }
272
- }, [auditLog, hasChecked, isLoading, pageName, operation, user?.id, effectiveScope, can]);
359
+ }, [auditLog, hasChecked, isLoading, pageName, operation, user?.id, effectiveScope, effectiveCan, isSuperAdmin]);
273
360
 
274
361
 
275
362
  // Handle strict mode violations
276
363
  useEffect(() => {
277
- if (strictMode && hasChecked && !isLoading && !can) {
364
+ if (strictMode && hasChecked && !isLoading && !effectiveCan && !shouldBypassScopeForSuperAdmin) {
278
365
  const logger = getRBACLogger();
279
366
  logger.error(`STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
280
367
  pageName,
@@ -286,20 +373,22 @@ const PagePermissionGuardComponent = ({
286
373
  scopeValid: allowsOptionalContexts ? true : (effectiveScope !== null), // PORTAL/ADMIN allow scope without org/event
287
374
  checkError,
288
375
  canError,
376
+ isSuperAdmin,
289
377
  timestamp: new Date().toISOString()
290
378
  });
291
379
  }
292
- }, [strictMode, hasChecked, isLoading, can, pageName, operation, effectivePageId, user?.id, effectiveScope, allowsOptionalContexts, checkError, canError]);
380
+ }, [strictMode, hasChecked, isLoading, effectiveCan, shouldBypassScopeForSuperAdmin, pageName, operation, effectivePageId, user?.id, effectiveScope, allowsOptionalContexts, checkError, canError, isSuperAdmin]);
293
381
 
294
382
  // Calculate the actual render state - FIXED: Proper state calculation
295
383
  // Add defensive checks to ensure we have valid state
296
384
  // For page-level permissions, PORTAL/ADMIN apps allow scope without org/event
297
- const hasValidScopeForPagePermissions = allowsOptionalContexts ? true : (effectiveScope !== null);
385
+ // Super admins bypass scope validation
386
+ const hasValidScopeForPagePermissions = shouldBypassScopeForSuperAdmin ? true : (allowsOptionalContexts ? true : (effectiveScope !== null));
298
387
  const hasValidUser = user && user.id;
299
388
  const isPermissionCheckComplete = hasChecked && !isLoading;
300
389
 
301
- const shouldShowAccessDenied = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && !can;
302
- const shouldShowContent = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && can;
390
+ const shouldShowAccessDenied = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && !effectiveCan;
391
+ const shouldShowContent = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && effectiveCan;
303
392
 
304
393
  // Create a key to force re-render when scope or permission state changes
305
394
  const scopeKey = effectiveScope ? `${effectiveScope.organisationId}-${effectiveScope.eventId}-${effectiveScope.appId}` : 'no-scope';
@@ -307,9 +396,60 @@ const PagePermissionGuardComponent = ({
307
396
 
308
397
 
309
398
 
399
+ // Debug logging for permission check state
400
+ useEffect(() => {
401
+ if (process.env.NODE_ENV === 'development') {
402
+ console.log('[PagePermissionGuard] Permission check state', {
403
+ pageName,
404
+ userId: user?.id,
405
+ isSuperAdmin,
406
+ isLoading,
407
+ scopeLoading,
408
+ canIsLoading,
409
+ hasChecked,
410
+ hasValidUser,
411
+ effectiveCan,
412
+ stableScope,
413
+ effectiveScope
414
+ });
415
+ }
416
+ }, [pageName, user?.id, isSuperAdmin, isLoading, scopeLoading, canIsLoading, hasChecked, hasValidUser, effectiveCan, stableScope, effectiveScope]);
417
+
310
418
  // Show loading state - if we're still loading or don't have valid state
311
419
  // For page-level permissions, we don't require organisation context, so only check for user and loading state
312
- if (isLoading || !hasValidUser || !hasChecked) {
420
+ // Add timeout warning for debugging
421
+ useEffect(() => {
422
+ if (isLoading && isSuperAdmin === null && hasValidUser) {
423
+ const timeout = setTimeout(() => {
424
+ console.warn('[PagePermissionGuard] Permission check taking longer than expected', {
425
+ pageName,
426
+ userId: user?.id,
427
+ isSuperAdmin,
428
+ scopeLoading,
429
+ canIsLoading,
430
+ hasChecked,
431
+ stableScope,
432
+ effectiveScope,
433
+ appName
434
+ });
435
+ }, 5000);
436
+ return () => clearTimeout(timeout);
437
+ }
438
+ }, [isLoading, isSuperAdmin, hasValidUser, pageName, user?.id, scopeLoading, canIsLoading, hasChecked, stableScope, effectiveScope, appName]);
439
+
440
+ // CRITICAL: Super admins bypass all checks - show content immediately once confirmed
441
+ // This must be checked AFTER all hooks are called to avoid React hooks rule violations
442
+ if (isSuperAdmin === true && hasValidUser) {
443
+ // Super admin confirmed - grant access immediately
444
+ console.log('[PagePermissionGuard] Super admin access granted - bypassing all checks', {
445
+ pageName,
446
+ userId: user?.id,
447
+ operation
448
+ });
449
+ return <>{children}</>;
450
+ }
451
+
452
+ if (isLoading || !hasValidUser || !hasChecked || isSuperAdmin === null) {
313
453
  return loading || <div>Checking permissions...</div>;
314
454
  }
315
455
 
@@ -49,7 +49,7 @@
49
49
  * - Cached permission checks
50
50
  *
51
51
  * @dependencies
52
- * - React 18+ - Context and hooks
52
+ * - React 19+ - Context and hooks
53
53
  * - useUnifiedAuth - Authentication context
54
54
  * - RBAC types - Type definitions
55
55
  */
@@ -60,7 +60,7 @@
60
60
  * - Efficient error handling
61
61
  *
62
62
  * @dependencies
63
- * - React 18+ - Component framework
63
+ * - React 19+ - Component framework
64
64
  * - useCan hook - Permission checking
65
65
  * - useUnifiedAuth - Authentication context
66
66
  * - RBAC types - Type definitions
@@ -56,7 +56,7 @@
56
56
  * - Efficient route matching
57
57
  *
58
58
  * @dependencies
59
- * - React 18+ - Component framework
59
+ * - React 19+ - Component framework
60
60
  * - React Router - Routing functionality
61
61
  * - useCan hook - Permission checking
62
62
  * - useUnifiedAuth - Authentication context
@@ -231,11 +231,15 @@ export function RoleBasedRouter({
231
231
  }, [user?.id, currentScope, routes]);
232
232
 
233
233
  // Use useCan hook for actual permission checking
234
+ // Pass null for super admin status (not checked yet - hook will check if needed)
234
235
  const { can: canAccessCurrentRoute, isLoading: permissionLoading } = useCan(
235
236
  user?.id || '',
236
237
  currentScope || { organisationId: '', eventId: undefined, appId: undefined },
237
238
  currentRouteConfig?.permissions?.[0] || 'read:page',
238
- currentRouteConfig?.pageId
239
+ currentRouteConfig?.pageId,
240
+ true, // useCache
241
+ null, // precomputedSuperAdmin - not checked yet
242
+ undefined // appName
239
243
  );
240
244
 
241
245
  // Check if route is public
@@ -12,7 +12,7 @@ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
12
12
  import React, { ReactNode } from 'react';
13
13
  import { SecureDataProvider, useSecureData } from './SecureDataProvider';
14
14
  import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
15
- import { useSecureDataAccess } from '../../hooks/useSecureDataAccess';
15
+ // useSecureDataAccess has been removed - SecureDataProvider now uses useSecureSupabase internally
16
16
  import { UUID, Scope, Permission } from '../types';
17
17
 
18
18
  // Mock the auth provider
@@ -23,8 +23,77 @@ vi.mock('../../providers/services/UnifiedAuthProvider', () => ({
23
23
  }));
24
24
 
25
25
  // Mock the secure data access hook
26
- vi.mock('../../hooks/useSecureDataAccess', () => ({
27
- useSecureDataAccess: vi.fn()
26
+ // useSecureDataAccess has been removed - no longer needed
27
+
28
+ // Mock useResolvedScope
29
+ const mockUseResolvedScopeFn = vi.fn();
30
+ vi.mock('../../hooks/useResolvedScope', () => ({
31
+ useResolvedScope: () => mockUseResolvedScopeFn(),
32
+ }));
33
+
34
+ // Mock useOrganisations to prevent provider requirement
35
+ vi.mock('../../hooks/useOrganisations', () => ({
36
+ useOrganisations: vi.fn(() => ({
37
+ organisations: [],
38
+ isLoading: false,
39
+ error: null,
40
+ refetch: vi.fn(),
41
+ selectedOrganisation: {
42
+ id: 'org-123',
43
+ name: 'Test Org',
44
+ display_name: 'Test Organisation',
45
+ description: 'Test',
46
+ subscription_tier: 'basic',
47
+ settings: {},
48
+ is_active: true,
49
+ created_at: '2023-01-01T00:00:00Z',
50
+ updated_at: '2023-01-01T00:00:00Z'
51
+ }
52
+ }))
53
+ }));
54
+
55
+ // Mock useEvents
56
+ vi.mock('../../hooks/useEvents', () => ({
57
+ useEvents: vi.fn(() => ({
58
+ events: [],
59
+ isLoading: false,
60
+ error: null,
61
+ refetch: vi.fn(),
62
+ selectedEvent: {
63
+ id: 'event-456',
64
+ event_id: 'event-456',
65
+ event_name: 'Test Event',
66
+ event_date: '2023-01-01T00:00:00Z',
67
+ event_venue: 'Test Venue',
68
+ event_participants: 100,
69
+ event_colours: '#FF0000',
70
+ event_logo: '',
71
+ organisation_id: 'org-123' as any,
72
+ is_visible: true,
73
+ created_at: '2023-01-01T00:00:00Z',
74
+ updated_at: '2023-01-01T00:00:00Z'
75
+ },
76
+ eventLoading: false
77
+ }))
78
+ }));
79
+
80
+ // Mock useOrganisationSecurity
81
+ vi.mock('../../hooks/useOrganisationSecurity', () => ({
82
+ useOrganisationSecurity: vi.fn(() => ({
83
+ superAdminContext: {
84
+ isSuperAdmin: false,
85
+ isLoading: false
86
+ },
87
+ organisationSecurity: {
88
+ canAccessOrganisation: vi.fn(() => true),
89
+ canAccessEvent: vi.fn(() => true)
90
+ }
91
+ }))
92
+ }));
93
+
94
+ // Mock useSecureSupabase
95
+ vi.mock('../hooks/useSecureSupabase', () => ({
96
+ useSecureSupabase: vi.fn((supabase) => supabase)
28
97
  }));
29
98
 
30
99
  // Mock the RBAC hooks
@@ -55,7 +124,7 @@ const TestComponent = ({ children }: { children: ReactNode }) => (
55
124
  );
56
125
 
57
126
  describe('SecureDataProvider', () => {
58
- const mockUseSecureDataAccess = vi.mocked(useSecureDataAccess);
127
+ // useSecureDataAccess has been removed
59
128
  const mockUseCan = vi.mocked(useCan);
60
129
 
61
130
  beforeEach(() => {
@@ -67,12 +136,7 @@ describe('SecureDataProvider', () => {
67
136
  // Add other required properties
68
137
  } as any);
69
138
 
70
- mockUseSecureDataAccess.mockReturnValue({
71
- isDataAccessAllowed: vi.fn().mockReturnValue(true),
72
- getDataAccessPermissions: vi.fn().mockReturnValue({}),
73
- validateDataAccess: vi.fn().mockReturnValue(true),
74
- // Add other required properties
75
- } as any);
139
+ // useSecureDataAccess has been removed - SecureDataProvider handles this internally
76
140
  });
77
141
 
78
142
  describe('Provider Initialization', () => {
@@ -160,12 +224,7 @@ describe('SecureDataProvider', () => {
160
224
  });
161
225
 
162
226
  it('denies data access when user lacks permissions', async () => {
163
- mockUseSecureDataAccess.mockReturnValue({
164
- isDataAccessAllowed: vi.fn().mockReturnValue(false),
165
- getDataAccessPermissions: vi.fn().mockReturnValue({}),
166
- validateDataAccess: vi.fn().mockReturnValue(false),
167
- // Add other required properties
168
- } as any);
227
+ // useSecureDataAccess has been removed - SecureDataProvider handles this internally
169
228
 
170
229
  const TestConsumer = () => {
171
230
  const context = useSecureData();
@@ -216,12 +275,7 @@ describe('SecureDataProvider', () => {
216
275
  'events': ['read', 'update']
217
276
  };
218
277
 
219
- mockUseSecureDataAccess.mockReturnValue({
220
- isDataAccessAllowed: vi.fn().mockReturnValue(true),
221
- getDataAccessPermissions: vi.fn().mockReturnValue(mockPermissions),
222
- validateDataAccess: vi.fn().mockReturnValue(true),
223
- // Add other required properties
224
- } as any);
278
+ // useSecureDataAccess has been removed - SecureDataProvider handles this internally
225
279
 
226
280
  const TestConsumer = () => {
227
281
  const context = useSecureData();
@@ -309,13 +363,7 @@ describe('SecureDataProvider', () => {
309
363
 
310
364
  it('calls onStrictModeViolation callback when strict mode is violated', async () => {
311
365
  const onStrictModeViolation = vi.fn();
312
- mockUseSecureDataAccess.mockReturnValue({
313
- isDataAccessAllowed: vi.fn().mockReturnValue(false),
314
- getDataAccessPermissions: vi.fn().mockReturnValue({}),
315
- validateDataAccess: vi.fn().mockReturnValue(false),
316
- // Add other required properties
317
- } as any);
318
-
366
+ // useSecureDataAccess has been removed - SecureDataProvider handles this internally
319
367
  const TestConsumer = () => {
320
368
  const context = useSecureData();
321
369
  context.isDataAccessAllowed('admin_users', 'delete', mockScope);
@@ -340,14 +388,7 @@ describe('SecureDataProvider', () => {
340
388
 
341
389
  describe('Error Handling', () => {
342
390
  it('handles data access validation errors gracefully', async () => {
343
- mockUseSecureDataAccess.mockReturnValue({
344
- isDataAccessAllowed: vi.fn().mockImplementation(() => {
345
- throw new Error('Data access validation failed');
346
- }),
347
- getDataAccessPermissions: vi.fn().mockReturnValue({}),
348
- validateDataAccess: vi.fn().mockReturnValue(false),
349
- // Add other required properties
350
- } as any);
391
+ // useSecureDataAccess has been removed - SecureDataProvider handles this internally
351
392
 
352
393
  const TestConsumer = () => {
353
394
  const context = useSecureData();
@@ -462,7 +503,7 @@ describe('SecureDataProvider', () => {
462
503
  });
463
504
 
464
505
  describe('Integration with useSecureDataAccess', () => {
465
- it('integrates with useSecureDataAccess hook', () => {
506
+ it('integrates with secure data access system', () => {
466
507
  const TestConsumer = () => {
467
508
  const context = useSecureData();
468
509
  context.isDataAccessAllowed(mockTable, mockOperation, mockScope);
@@ -476,19 +517,12 @@ describe('SecureDataProvider', () => {
476
517
  </SecureDataProvider>
477
518
  );
478
519
 
479
- expect(mockUseSecureDataAccess).toHaveBeenCalled();
520
+ // useSecureDataAccess has been removed - this test verifies the component works
521
+ // expect(mockUseSecureDataAccess).toHaveBeenCalled();
480
522
  });
481
523
 
482
524
  it('passes through secure data access functionality', () => {
483
- const mockSecureDataAccess = {
484
- isDataAccessAllowed: vi.fn().mockReturnValue(true),
485
- getDataAccessPermissions: vi.fn().mockReturnValue({}),
486
- validateDataAccess: vi.fn().mockReturnValue(true),
487
- // Add other required properties
488
- };
489
-
490
- mockUseSecureDataAccess.mockReturnValue(mockSecureDataAccess as any);
491
-
525
+ // useSecureDataAccess has been removed - SecureDataProvider handles this internally
492
526
  const TestConsumer = () => {
493
527
  const context = useSecureData();
494
528
  context.isDataAccessAllowed(mockTable, mockOperation, mockScope);
@@ -502,7 +536,8 @@ describe('SecureDataProvider', () => {
502
536
  </SecureDataProvider>
503
537
  );
504
538
 
505
- expect(mockSecureDataAccess.isDataAccessAllowed).not.toHaveBeenCalled();
539
+ // Component should render without errors
540
+ expect(screen.getByText('Test')).toBeInTheDocument();
506
541
  });
507
542
  });
508
543
  });
@@ -50,15 +50,16 @@
50
50
  * - Cached permission checks
51
51
  *
52
52
  * @dependencies
53
- * - React 18+ - Context and hooks
53
+ * - React 19+ - Context and hooks
54
54
  * - useUnifiedAuth - Authentication context
55
- * - useSecureDataAccess - Secure data access hook
55
+ * - useSecureSupabase - Secure Supabase client hook
56
56
  * - RBAC types - Type definitions
57
57
  */
58
58
 
59
59
  import React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
60
60
  import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
61
- import { useSecureDataAccess } from '../../hooks/useSecureDataAccess';
61
+ import { useSecureSupabase } from '../hooks/useSecureSupabase';
62
+ import { useOrganisationSecurity } from '../../hooks/useOrganisationSecurity';
62
63
  import { useResolvedScope } from '../hooks/useResolvedScope';
63
64
  import { UUID, Scope, Permission } from '../types';
64
65
  import { getRBACLogger } from '../config';
@@ -144,7 +145,8 @@ export function SecureDataProvider({
144
145
  enforceRLS = true
145
146
  }: SecureDataProviderProps) {
146
147
  const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
147
- const { validateContext } = useSecureDataAccess();
148
+ const secureSupabase = useSecureSupabase(supabase);
149
+ const { superAdminContext } = useOrganisationSecurity();
148
150
  const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);
149
151
  const [isEnabled, setIsEnabled] = useState(true);
150
152
 
@@ -154,6 +156,19 @@ export function SecureDataProvider({
154
156
  selectedOrganisationId: selectedOrganisation?.id || null,
155
157
  selectedEventId: selectedEvent?.event_id || null
156
158
  });
159
+
160
+ // Validate context - similar to useSecureDataAccess.validateContext
161
+ const validateContext = useCallback((): void => {
162
+ if (!secureSupabase) {
163
+ throw new Error('No Supabase client available');
164
+ }
165
+ if (!user) {
166
+ throw new Error('User must be authenticated');
167
+ }
168
+ if (!superAdminContext.isSuperAdmin && !resolvedScope?.organisationId) {
169
+ throw new Error('Organisation context is required for data access');
170
+ }
171
+ }, [secureSupabase, user, superAdminContext.isSuperAdmin, resolvedScope?.organisationId]);
157
172
 
158
173
  // Get current scope from resolved scope
159
174
  // For event-required apps: org is derived from event
@@ -174,10 +189,10 @@ export function SecureDataProvider({
174
189
 
175
190
  // Use the existing RBAC system to check data access permissions
176
191
  // This is a synchronous check for the context - actual permission checking
177
- // happens in the useSecureDataAccess hook using the RBAC engine
192
+ // happens using the RBAC engine via useSecureSupabase
178
193
  const permission = `${operation}:data.${table}` as Permission;
179
194
 
180
- // For now, we'll return true and let the useSecureDataAccess hook
195
+ // For now, we'll return true and let the RBAC system
181
196
  // handle the actual permission checking asynchronously
182
197
  // This context is mainly for tracking and audit purposes
183
198
  return true;