@jmruthers/pace-core 0.6.1 → 0.6.3

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 (549) hide show
  1. package/CHANGELOG.md +88 -10
  2. package/cursor-rules/00-pace-core-compliance.mdc +46 -87
  3. package/cursor-rules/01-standards-compliance.mdc +16 -47
  4. package/cursor-rules/02-project-structure.mdc +4 -4
  5. package/cursor-rules/03-solid-principles.mdc +45 -164
  6. package/cursor-rules/04-testing-standards.mdc +22 -69
  7. package/cursor-rules/05-bug-reports-and-features.mdc +2 -2
  8. package/cursor-rules/06-code-quality.mdc +42 -125
  9. package/cursor-rules/07-tech-stack-compliance.mdc +33 -128
  10. package/cursor-rules/08-markup-quality.mdc +452 -0
  11. package/cursor-rules/CHANGELOG.md +18 -0
  12. package/cursor-rules/README.md +2 -1
  13. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-Cb34EQs3.d.ts} +63 -1
  14. package/dist/{DataTable-CH1U5Tpy.d.ts → DataTable-BMRU8a1j.d.ts} +33 -1
  15. package/dist/{DataTable-DQ7RSOHE.js → DataTable-THFPBKTP.js} +12 -10
  16. package/dist/{PublicPageProvider-ce4xlHYA.d.ts → PublicPageProvider-DEMpysFR.d.ts} +394 -171
  17. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CKvHP1MK.d.ts} +30 -8
  18. package/dist/{UnifiedAuthProvider-ATAP5UTR.js → UnifiedAuthProvider-KAGUYQ4J.js} +5 -4
  19. package/dist/{api-N774RPUA.js → api-IAGWF3ZG.js} +10 -10
  20. package/dist/{audit-B5P6FFIR.js → audit-V53FV5AG.js} +2 -2
  21. package/dist/{chunk-JBKQ3SAO.js → chunk-2T2IG7T7.js} +107 -57
  22. package/dist/chunk-2T2IG7T7.js.map +1 -0
  23. package/dist/{chunk-3QRJFVBR.js → chunk-6SOIHG6Z.js} +1 -1
  24. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  25. package/dist/{chunk-3XTALGJF.js → chunk-6Z7LTB3D.js} +69 -240
  26. package/dist/chunk-6Z7LTB3D.js.map +1 -0
  27. package/dist/{chunk-4ZC4GX36.js → chunk-CNCQDFLN.js} +199 -46
  28. package/dist/chunk-CNCQDFLN.js.map +1 -0
  29. package/dist/chunk-DGUM43GV.js +11 -0
  30. package/dist/{chunk-BYFSK72L.js → chunk-DWUBLJJM.js} +361 -187
  31. package/dist/chunk-DWUBLJJM.js.map +1 -0
  32. package/dist/{chunk-LXQLPRQ2.js → chunk-FFQEQTNW.js} +6 -8
  33. package/dist/chunk-FFQEQTNW.js.map +1 -0
  34. package/dist/chunk-FMUCXFII.js +76 -0
  35. package/dist/chunk-FMUCXFII.js.map +1 -0
  36. package/dist/{chunk-4N5C5XZU.js → chunk-HFZBI76P.js} +4 -4
  37. package/dist/chunk-HFZBI76P.js.map +1 -0
  38. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  39. package/dist/chunk-L4OXEN46.js.map +1 -0
  40. package/dist/{chunk-R77UEZ4E.js → chunk-M43Y4SSO.js} +1 -1
  41. package/dist/chunk-M43Y4SSO.js.map +1 -0
  42. package/dist/{chunk-I7PSE6JW.js → chunk-M7MPQISP.js} +3 -76
  43. package/dist/chunk-M7MPQISP.js.map +1 -0
  44. package/dist/chunk-PQBSKX33.js +7793 -0
  45. package/dist/chunk-PQBSKX33.js.map +1 -0
  46. package/dist/chunk-QRPVRXYT.js +226 -0
  47. package/dist/chunk-QRPVRXYT.js.map +1 -0
  48. package/dist/{chunk-KNC55RTG.js → chunk-RWEBCB47.js} +194 -416
  49. package/dist/chunk-RWEBCB47.js.map +1 -0
  50. package/dist/{chunk-XM25TVIE.js → chunk-YDQHOZNA.js} +843 -388
  51. package/dist/chunk-YDQHOZNA.js.map +1 -0
  52. package/dist/{chunk-GLK6VM3F.js → chunk-ZNIWI3UC.js} +739 -737
  53. package/dist/chunk-ZNIWI3UC.js.map +1 -0
  54. package/dist/components.d.ts +5 -5
  55. package/dist/components.js +18 -16
  56. package/dist/components.js.map +1 -1
  57. package/dist/contextValidator-3JNZKUTX.js +9 -0
  58. package/dist/contextValidator-3JNZKUTX.js.map +1 -0
  59. package/dist/eslint-rules/pace-core-compliance.cjs +106 -0
  60. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  61. package/dist/hooks.d.ts +55 -122
  62. package/dist/hooks.js +10 -13
  63. package/dist/hooks.js.map +1 -1
  64. package/dist/index.d.ts +60 -13
  65. package/dist/index.js +30 -25
  66. package/dist/index.js.map +1 -1
  67. package/dist/providers.d.ts +21 -3
  68. package/dist/providers.js +4 -3
  69. package/dist/rbac/index.d.ts +210 -139
  70. package/dist/rbac/index.js +17 -13
  71. package/dist/styles/index.js +1 -1
  72. package/dist/theming/runtime.d.ts +1 -13
  73. package/dist/theming/runtime.js +2 -2
  74. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  75. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  76. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  77. package/dist/types.d.ts +2 -2
  78. package/dist/types.js +1 -1
  79. package/dist/{usePublicRouteParams-BJAlWfuJ.d.ts → usePublicRouteParams-i3qtoBgg.d.ts} +38 -17
  80. package/dist/utils.d.ts +4 -5
  81. package/dist/utils.js +17 -19
  82. package/dist/utils.js.map +1 -1
  83. package/docs/api/README.md +21 -17
  84. package/docs/api/modules.md +4191 -2967
  85. package/docs/architecture/database-schema-requirements.md +161 -0
  86. package/docs/components/context-selector.md +126 -0
  87. package/docs/core-concepts/rbac-system.md +3 -3
  88. package/docs/documentation-index.md +2 -4
  89. package/docs/getting-started/cursor-rules.md +2 -1
  90. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  91. package/docs/migration/MIGRATION_GUIDE.md +2 -24
  92. package/docs/migration/RBAC_SCOPE_MIGRATION.md +385 -0
  93. package/docs/migration/README.md +52 -6
  94. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  95. package/docs/migration/database-changes-december-2025.md +3 -3
  96. package/docs/pace-mint-fix-auto-selection.md +218 -0
  97. package/docs/pace-mint-rbac-setup.md +391 -0
  98. package/docs/rbac/event-based-apps.md +1 -1
  99. package/docs/rbac/getting-started.md +1 -1
  100. package/docs/rbac/quick-start.md +1 -1
  101. package/docs/rbac/secure-client-protection.md +330 -0
  102. package/docs/standards/README.md +1 -0
  103. package/package.json +4 -3
  104. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  105. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  106. package/scripts/audit/core/checks/bundle.cjs +142 -0
  107. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +784 -685
  108. package/scripts/audit/core/checks/config.cjs +54 -0
  109. package/scripts/audit/core/checks/coverage.cjs +84 -0
  110. package/scripts/audit/core/checks/dependencies.cjs +985 -0
  111. package/scripts/audit/core/checks/documentation.cjs +268 -0
  112. package/scripts/audit/core/checks/environment.cjs +116 -0
  113. package/scripts/audit/core/checks/error-handling.cjs +340 -0
  114. package/scripts/audit/core/checks/forms.cjs +172 -0
  115. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  116. package/scripts/audit/core/checks/hooks.cjs +334 -0
  117. package/scripts/audit/core/checks/imports.cjs +244 -0
  118. package/scripts/audit/core/checks/performance.cjs +325 -0
  119. package/scripts/audit/core/checks/routes.cjs +117 -0
  120. package/scripts/audit/core/checks/state.cjs +130 -0
  121. package/scripts/audit/core/checks/structure.cjs +65 -0
  122. package/scripts/audit/core/checks/style.cjs +584 -0
  123. package/scripts/audit/core/checks/testing.cjs +122 -0
  124. package/scripts/audit/core/checks/typescript.cjs +61 -0
  125. package/scripts/audit/core/scanner.cjs +199 -0
  126. package/scripts/audit/core/utils.cjs +137 -0
  127. package/scripts/audit/index.cjs +223 -0
  128. package/scripts/audit/reporters/console.cjs +151 -0
  129. package/scripts/audit/reporters/json.cjs +54 -0
  130. package/scripts/audit/reporters/markdown.cjs +124 -0
  131. package/scripts/audit-consuming-app.cjs +61 -936
  132. package/scripts/build-docs/build-decision.js +240 -0
  133. package/scripts/build-docs/cache-utils.js +105 -0
  134. package/scripts/build-docs/content-normalization.js +150 -0
  135. package/scripts/build-docs/file-utils.js +105 -0
  136. package/scripts/build-docs/git-utils.js +86 -0
  137. package/scripts/build-docs/hash-utils.js +116 -0
  138. package/scripts/build-docs/typedoc-runner.js +220 -0
  139. package/scripts/build-docs-incremental.js +77 -913
  140. package/scripts/utils/command-runner.js +16 -11
  141. package/scripts/validate-formats.js +61 -56
  142. package/scripts/validate-master.js +74 -69
  143. package/scripts/validate-pre-publish.js +70 -65
  144. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  145. package/src/components/Alert/Alert.test.tsx +12 -18
  146. package/src/components/Alert/Alert.tsx +5 -7
  147. package/src/components/Avatar/Avatar.test.tsx +4 -4
  148. package/src/components/Badge/Badge.tsx +14 -0
  149. package/src/components/Button/Button.tsx +22 -0
  150. package/src/components/Calendar/Calendar.tsx +8 -2
  151. package/src/components/Card/Card.tsx +4 -0
  152. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  153. package/src/components/Checkbox/Checkbox.tsx +2 -2
  154. package/src/components/ContextSelector/ContextSelector.tsx +384 -0
  155. package/src/components/ContextSelector/index.ts +3 -0
  156. package/src/components/DataTable/DataTable.tsx +38 -4
  157. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  158. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +18 -4
  159. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  160. package/src/components/DataTable/components/AccessDeniedPage.tsx +16 -25
  161. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  162. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +1 -1
  163. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  164. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  165. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  166. package/src/components/DataTable/components/DataTableCore.tsx +196 -554
  167. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  168. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  169. package/src/components/DataTable/components/DataTableModals.tsx +8 -0
  170. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  171. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  172. package/src/components/DataTable/components/EditFields.tsx +307 -0
  173. package/src/components/DataTable/components/EditableRow.tsx +8 -0
  174. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  175. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  176. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  177. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  178. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  179. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  180. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  181. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  182. package/src/components/DataTable/components/UnifiedTableBody.tsx +63 -851
  183. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  184. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  185. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  186. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  187. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  188. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  189. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  190. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  191. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  192. package/src/components/DataTable/hooks/useColumnReordering.ts +12 -0
  193. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  194. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  195. package/src/components/DataTable/hooks/useDataTablePermissions.ts +127 -33
  196. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  197. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  198. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  199. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  200. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  201. package/src/components/DataTable/styles.ts +6 -6
  202. package/src/components/DataTable/types.ts +6 -10
  203. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  204. package/src/components/DataTable/utils/debugTools.ts +18 -113
  205. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  206. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  207. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  208. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  209. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  210. package/src/components/Dialog/Dialog.tsx +31 -3
  211. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  212. package/src/components/ErrorBoundary/ErrorBoundary.tsx +45 -5
  213. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  214. package/src/components/ErrorBoundary/index.ts +27 -2
  215. package/src/components/FileDisplay/FileDisplay.tsx +74 -28
  216. package/src/components/FileUpload/FileUpload.tsx +22 -2
  217. package/src/components/Footer/Footer.test.tsx +16 -16
  218. package/src/components/Footer/Footer.tsx +14 -11
  219. package/src/components/Form/Form.tsx +1 -0
  220. package/src/components/Header/Header.test.tsx +43 -73
  221. package/src/components/Header/Header.tsx +59 -49
  222. package/src/components/Input/Input.test.tsx +2 -2
  223. package/src/components/Input/Input.tsx +8 -4
  224. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  225. package/src/components/LoginForm/LoginForm.tsx +4 -0
  226. package/src/components/NavigationMenu/NavigationMenu.tsx +14 -513
  227. package/src/components/NavigationMenu/types.ts +56 -0
  228. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  229. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +10 -19
  230. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +2 -2
  231. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +5 -5
  232. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +13 -11
  233. package/src/components/PaceAppLayout/PaceAppLayout.tsx +167 -44
  234. package/src/components/PaceAppLayout/README.md +14 -17
  235. package/src/components/PaceAppLayout/test-setup.tsx +3 -4
  236. package/src/components/PaceLoginPage/PaceLoginPage.tsx +3 -0
  237. package/src/components/PasswordChange/PasswordChangeForm.tsx +9 -0
  238. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  239. package/src/components/PublicLayout/PublicPageLayout.tsx +2 -5
  240. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  241. package/src/components/Select/Select.tsx +80 -434
  242. package/src/components/Select/context.ts +23 -0
  243. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  244. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  245. package/src/components/Select/hooks/useSelectState.ts +104 -0
  246. package/src/components/Select/index.ts +9 -1
  247. package/src/components/Select/types.ts +123 -0
  248. package/src/components/Select/utils/text.ts +26 -0
  249. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +4 -5
  250. package/src/components/Switch/Switch.tsx +4 -4
  251. package/src/components/Tabs/Tabs.tsx +1 -1
  252. package/src/components/Toast/Toast.tsx +4 -0
  253. package/src/components/Tooltip/Tooltip.tsx +2 -2
  254. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  255. package/src/components/UserMenu/UserMenu.tsx +21 -18
  256. package/src/components/index.ts +7 -7
  257. package/src/eslint-rules/pace-core-compliance.cjs +106 -0
  258. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  259. package/src/hooks/__tests__/useAppConfig.unit.test.ts +4 -98
  260. package/src/hooks/index.ts +1 -2
  261. package/src/hooks/public/usePublicEvent.ts +4 -0
  262. package/src/hooks/public/usePublicEventLogo.ts +4 -0
  263. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  264. package/src/hooks/public/usePublicRouteParams.ts +4 -0
  265. package/src/hooks/services/useAuth.ts +32 -0
  266. package/src/hooks/services/useCurrentEvent.ts +6 -0
  267. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  268. package/src/hooks/useAppConfig.ts +15 -30
  269. package/src/hooks/useDebounce.ts +9 -0
  270. package/src/hooks/useEventTheme.ts +6 -0
  271. package/src/hooks/useFileDisplay.ts +81 -50
  272. package/src/hooks/useFileReference.ts +25 -7
  273. package/src/hooks/useFileUrl.ts +11 -1
  274. package/src/hooks/useFocusManagement.ts +14 -0
  275. package/src/hooks/useFocusTrap.ts +3 -0
  276. package/src/hooks/useInactivityTracker.ts +3 -0
  277. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  278. package/src/hooks/useOrganisationPermissions.ts +4 -0
  279. package/src/hooks/useOrganisationSecurity.ts +4 -0
  280. package/src/hooks/usePerformanceMonitor.ts +4 -0
  281. package/src/hooks/usePermissionCache.ts +7 -0
  282. package/src/hooks/useQueryCache.ts +12 -1
  283. package/src/hooks/useSessionRestoration.ts +4 -0
  284. package/src/hooks/useStorage.ts +4 -0
  285. package/src/hooks/useToast.ts +1 -1
  286. package/src/index.ts +6 -6
  287. package/src/providers/__tests__/OrganisationProvider.test.tsx +92 -70
  288. package/src/providers/services/AuthServiceProvider.tsx +35 -7
  289. package/src/providers/services/EventServiceProvider.tsx +51 -5
  290. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  291. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  292. package/src/providers/services/UnifiedAuthProvider.tsx +126 -134
  293. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +29 -13
  294. package/src/rbac/README.md +1 -1
  295. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +1 -1
  296. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  297. package/src/rbac/adapters.tsx +12 -3
  298. package/src/rbac/api.test.ts +59 -51
  299. package/src/rbac/api.ts +246 -167
  300. package/src/rbac/components/NavigationProvider.tsx +4 -1
  301. package/src/rbac/components/PagePermissionGuard.tsx +185 -17
  302. package/src/rbac/components/RoleBasedRouter.tsx +5 -1
  303. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  304. package/src/rbac/components/SecureDataProvider.tsx +20 -5
  305. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  306. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  307. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  308. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  309. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  310. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  311. package/src/rbac/engine.ts +38 -14
  312. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +32 -21
  313. package/src/rbac/hooks/permissions/index.ts +7 -0
  314. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  315. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  316. package/src/rbac/hooks/permissions/useCan.ts +377 -0
  317. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  318. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  319. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  320. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  321. package/src/rbac/hooks/useCan.test.ts +64 -66
  322. package/src/rbac/hooks/usePermissions.ts +14 -995
  323. package/src/rbac/hooks/useRBAC.test.ts +1 -5
  324. package/src/rbac/hooks/useRBAC.ts +36 -37
  325. package/src/rbac/hooks/useResolvedScope.test.ts +120 -35
  326. package/src/rbac/hooks/useResolvedScope.ts +35 -40
  327. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  328. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  329. package/src/rbac/hooks/useSecureSupabase.ts +27 -7
  330. package/src/rbac/index.ts +7 -0
  331. package/src/rbac/permissions.ts +0 -30
  332. package/src/rbac/secureClient.test.ts +22 -18
  333. package/src/rbac/secureClient.ts +294 -68
  334. package/src/rbac/security.ts +0 -17
  335. package/src/rbac/types.ts +9 -0
  336. package/src/rbac/utils/__tests__/contextValidator.test.ts +64 -86
  337. package/src/rbac/utils/clientSecurity.ts +93 -0
  338. package/src/rbac/utils/contextValidator.ts +77 -168
  339. package/src/services/AuthService.ts +39 -7
  340. package/src/services/EventService.ts +186 -54
  341. package/src/services/OrganisationService.ts +81 -14
  342. package/src/services/__tests__/EventService.test.ts +1 -2
  343. package/src/services/base/BaseService.ts +3 -0
  344. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  345. package/src/theming/parseEventColours.ts +5 -19
  346. package/src/types/vitest-globals.d.ts +51 -26
  347. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  348. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  349. package/src/utils/__tests__/index.unit.test.ts +2 -2
  350. package/src/utils/audit/audit.ts +0 -3
  351. package/src/utils/core/cn.ts +1 -1
  352. package/src/utils/dynamic/dynamicUtils.ts +7 -4
  353. package/src/utils/file-reference/index.ts +53 -1
  354. package/src/utils/formatting/formatting.ts +8 -18
  355. package/src/utils/index.ts +0 -1
  356. package/dist/chunk-3QRJFVBR.js.map +0 -1
  357. package/dist/chunk-3XTALGJF.js.map +0 -1
  358. package/dist/chunk-4N5C5XZU.js.map +0 -1
  359. package/dist/chunk-4ZC4GX36.js.map +0 -1
  360. package/dist/chunk-7D4SUZUM.js +0 -38
  361. package/dist/chunk-BYFSK72L.js.map +0 -1
  362. package/dist/chunk-EXUD6RNJ.js +0 -451
  363. package/dist/chunk-EXUD6RNJ.js.map +0 -1
  364. package/dist/chunk-GLK6VM3F.js.map +0 -1
  365. package/dist/chunk-I7PSE6JW.js.map +0 -1
  366. package/dist/chunk-JBKQ3SAO.js.map +0 -1
  367. package/dist/chunk-KNC55RTG.js.map +0 -1
  368. package/dist/chunk-LXQLPRQ2.js.map +0 -1
  369. package/dist/chunk-R77UEZ4E.js.map +0 -1
  370. package/dist/chunk-SQGMNID3.js.map +0 -1
  371. package/dist/chunk-T33XF5ZC.js +0 -12922
  372. package/dist/chunk-T33XF5ZC.js.map +0 -1
  373. package/dist/chunk-XM25TVIE.js.map +0 -1
  374. package/docs/api/classes/ColumnFactory.md +0 -243
  375. package/docs/api/classes/ErrorBoundary.md +0 -144
  376. package/docs/api/classes/InvalidScopeError.md +0 -73
  377. package/docs/api/classes/Logger.md +0 -178
  378. package/docs/api/classes/MissingUserContextError.md +0 -66
  379. package/docs/api/classes/OrganisationContextRequiredError.md +0 -66
  380. package/docs/api/classes/PermissionDeniedError.md +0 -73
  381. package/docs/api/classes/RBACAuditManager.md +0 -297
  382. package/docs/api/classes/RBACCache.md +0 -322
  383. package/docs/api/classes/RBACEngine.md +0 -171
  384. package/docs/api/classes/RBACError.md +0 -76
  385. package/docs/api/classes/RBACNotInitializedError.md +0 -66
  386. package/docs/api/classes/SecureSupabaseClient.md +0 -160
  387. package/docs/api/classes/StorageUtils.md +0 -328
  388. package/docs/api/enums/FileCategory.md +0 -184
  389. package/docs/api/enums/LogLevel.md +0 -54
  390. package/docs/api/enums/RBACErrorCode.md +0 -228
  391. package/docs/api/enums/RPCFunction.md +0 -118
  392. package/docs/api/interfaces/AddressFieldProps.md +0 -241
  393. package/docs/api/interfaces/AddressFieldRef.md +0 -94
  394. package/docs/api/interfaces/AggregateConfig.md +0 -43
  395. package/docs/api/interfaces/AutocompleteOptions.md +0 -75
  396. package/docs/api/interfaces/AvatarProps.md +0 -128
  397. package/docs/api/interfaces/BadgeProps.md +0 -27
  398. package/docs/api/interfaces/ButtonProps.md +0 -53
  399. package/docs/api/interfaces/CalendarProps.md +0 -70
  400. package/docs/api/interfaces/CardProps.md +0 -66
  401. package/docs/api/interfaces/ColorPalette.md +0 -7
  402. package/docs/api/interfaces/ColorShade.md +0 -66
  403. package/docs/api/interfaces/ComplianceResult.md +0 -30
  404. package/docs/api/interfaces/DataAccessRecord.md +0 -96
  405. package/docs/api/interfaces/DataRecord.md +0 -11
  406. package/docs/api/interfaces/DataTableAction.md +0 -249
  407. package/docs/api/interfaces/DataTableColumn.md +0 -504
  408. package/docs/api/interfaces/DataTableProps.md +0 -625
  409. package/docs/api/interfaces/DataTableToolbarButton.md +0 -96
  410. package/docs/api/interfaces/DatabaseComplianceResult.md +0 -85
  411. package/docs/api/interfaces/DatabaseIssue.md +0 -41
  412. package/docs/api/interfaces/EmptyStateConfig.md +0 -61
  413. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +0 -235
  414. package/docs/api/interfaces/EventAppRoleData.md +0 -71
  415. package/docs/api/interfaces/ExportColumn.md +0 -90
  416. package/docs/api/interfaces/ExportOptions.md +0 -126
  417. package/docs/api/interfaces/FileDisplayProps.md +0 -249
  418. package/docs/api/interfaces/FileMetadata.md +0 -129
  419. package/docs/api/interfaces/FileReference.md +0 -118
  420. package/docs/api/interfaces/FileSizeLimits.md +0 -7
  421. package/docs/api/interfaces/FileUploadOptions.md +0 -139
  422. package/docs/api/interfaces/FileUploadProps.md +0 -293
  423. package/docs/api/interfaces/FooterProps.md +0 -105
  424. package/docs/api/interfaces/FormFieldProps.md +0 -166
  425. package/docs/api/interfaces/FormProps.md +0 -113
  426. package/docs/api/interfaces/GrantEventAppRoleParams.md +0 -122
  427. package/docs/api/interfaces/InactivityWarningModalProps.md +0 -115
  428. package/docs/api/interfaces/InputProps.md +0 -53
  429. package/docs/api/interfaces/LabelProps.md +0 -107
  430. package/docs/api/interfaces/LoggerConfig.md +0 -62
  431. package/docs/api/interfaces/LoginFormProps.md +0 -184
  432. package/docs/api/interfaces/NavigationAccessRecord.md +0 -107
  433. package/docs/api/interfaces/NavigationContextType.md +0 -164
  434. package/docs/api/interfaces/NavigationGuardProps.md +0 -139
  435. package/docs/api/interfaces/NavigationItem.md +0 -120
  436. package/docs/api/interfaces/NavigationMenuProps.md +0 -221
  437. package/docs/api/interfaces/NavigationProviderProps.md +0 -117
  438. package/docs/api/interfaces/Organisation.md +0 -140
  439. package/docs/api/interfaces/OrganisationContextType.md +0 -388
  440. package/docs/api/interfaces/OrganisationMembership.md +0 -140
  441. package/docs/api/interfaces/OrganisationProviderProps.md +0 -76
  442. package/docs/api/interfaces/OrganisationSecurityError.md +0 -62
  443. package/docs/api/interfaces/PaceAppLayoutProps.md +0 -406
  444. package/docs/api/interfaces/PaceLoginPageProps.md +0 -47
  445. package/docs/api/interfaces/PageAccessRecord.md +0 -85
  446. package/docs/api/interfaces/PagePermissionContextType.md +0 -140
  447. package/docs/api/interfaces/PagePermissionGuardProps.md +0 -153
  448. package/docs/api/interfaces/PagePermissionProviderProps.md +0 -119
  449. package/docs/api/interfaces/PaletteData.md +0 -41
  450. package/docs/api/interfaces/ParsedAddress.md +0 -120
  451. package/docs/api/interfaces/PermissionEnforcerProps.md +0 -153
  452. package/docs/api/interfaces/ProgressProps.md +0 -42
  453. package/docs/api/interfaces/ProtectedRouteProps.md +0 -97
  454. package/docs/api/interfaces/PublicPageFooterProps.md +0 -112
  455. package/docs/api/interfaces/PublicPageHeaderProps.md +0 -125
  456. package/docs/api/interfaces/PublicPageLayoutProps.md +0 -198
  457. package/docs/api/interfaces/QuickFix.md +0 -52
  458. package/docs/api/interfaces/RBACAccessValidateParams.md +0 -52
  459. package/docs/api/interfaces/RBACAccessValidateResult.md +0 -41
  460. package/docs/api/interfaces/RBACAuditLogParams.md +0 -85
  461. package/docs/api/interfaces/RBACAuditLogResult.md +0 -52
  462. package/docs/api/interfaces/RBACConfig.md +0 -133
  463. package/docs/api/interfaces/RBACContext.md +0 -52
  464. package/docs/api/interfaces/RBACLogger.md +0 -112
  465. package/docs/api/interfaces/RBACPageAccessCheckParams.md +0 -74
  466. package/docs/api/interfaces/RBACPerformanceMetrics.md +0 -138
  467. package/docs/api/interfaces/RBACPermissionCheckParams.md +0 -74
  468. package/docs/api/interfaces/RBACPermissionCheckResult.md +0 -52
  469. package/docs/api/interfaces/RBACPermissionsGetParams.md +0 -63
  470. package/docs/api/interfaces/RBACPermissionsGetResult.md +0 -63
  471. package/docs/api/interfaces/RBACResult.md +0 -58
  472. package/docs/api/interfaces/RBACRoleGrantParams.md +0 -63
  473. package/docs/api/interfaces/RBACRoleGrantResult.md +0 -52
  474. package/docs/api/interfaces/RBACRoleRevokeParams.md +0 -63
  475. package/docs/api/interfaces/RBACRoleRevokeResult.md +0 -52
  476. package/docs/api/interfaces/RBACRoleValidateParams.md +0 -52
  477. package/docs/api/interfaces/RBACRoleValidateResult.md +0 -63
  478. package/docs/api/interfaces/RBACRolesListParams.md +0 -52
  479. package/docs/api/interfaces/RBACRolesListResult.md +0 -74
  480. package/docs/api/interfaces/RBACSessionTrackParams.md +0 -74
  481. package/docs/api/interfaces/RBACSessionTrackResult.md +0 -52
  482. package/docs/api/interfaces/ResourcePermissions.md +0 -155
  483. package/docs/api/interfaces/RevokeEventAppRoleParams.md +0 -100
  484. package/docs/api/interfaces/RoleBasedRouterContextType.md +0 -151
  485. package/docs/api/interfaces/RoleBasedRouterProps.md +0 -156
  486. package/docs/api/interfaces/RoleManagementResult.md +0 -52
  487. package/docs/api/interfaces/RouteAccessRecord.md +0 -107
  488. package/docs/api/interfaces/RouteConfig.md +0 -134
  489. package/docs/api/interfaces/RuntimeComplianceResult.md +0 -55
  490. package/docs/api/interfaces/SecureDataContextType.md +0 -168
  491. package/docs/api/interfaces/SecureDataProviderProps.md +0 -132
  492. package/docs/api/interfaces/SessionRestorationLoaderProps.md +0 -34
  493. package/docs/api/interfaces/SetupIssue.md +0 -41
  494. package/docs/api/interfaces/StorageConfig.md +0 -41
  495. package/docs/api/interfaces/StorageFileInfo.md +0 -74
  496. package/docs/api/interfaces/StorageFileMetadata.md +0 -151
  497. package/docs/api/interfaces/StorageListOptions.md +0 -99
  498. package/docs/api/interfaces/StorageListResult.md +0 -41
  499. package/docs/api/interfaces/StorageUploadOptions.md +0 -101
  500. package/docs/api/interfaces/StorageUploadResult.md +0 -63
  501. package/docs/api/interfaces/StorageUrlOptions.md +0 -60
  502. package/docs/api/interfaces/StyleImport.md +0 -19
  503. package/docs/api/interfaces/SwitchProps.md +0 -34
  504. package/docs/api/interfaces/TabsContentProps.md +0 -9
  505. package/docs/api/interfaces/TabsListProps.md +0 -9
  506. package/docs/api/interfaces/TabsProps.md +0 -9
  507. package/docs/api/interfaces/TabsTriggerProps.md +0 -50
  508. package/docs/api/interfaces/TextareaProps.md +0 -53
  509. package/docs/api/interfaces/ToastActionElement.md +0 -9
  510. package/docs/api/interfaces/ToastProps.md +0 -9
  511. package/docs/api/interfaces/UnifiedAuthContextType.md +0 -820
  512. package/docs/api/interfaces/UnifiedAuthProviderProps.md +0 -171
  513. package/docs/api/interfaces/UseFormDialogOptions.md +0 -62
  514. package/docs/api/interfaces/UseFormDialogReturn.md +0 -117
  515. package/docs/api/interfaces/UseInactivityTrackerOptions.md +0 -136
  516. package/docs/api/interfaces/UseInactivityTrackerReturn.md +0 -123
  517. package/docs/api/interfaces/UsePublicEventLogoOptions.md +0 -87
  518. package/docs/api/interfaces/UsePublicEventLogoReturn.md +0 -81
  519. package/docs/api/interfaces/UsePublicEventOptions.md +0 -34
  520. package/docs/api/interfaces/UsePublicEventReturn.md +0 -68
  521. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +0 -47
  522. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +0 -120
  523. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +0 -94
  524. package/docs/api/interfaces/UseResolvedScopeOptions.md +0 -47
  525. package/docs/api/interfaces/UseResolvedScopeReturn.md +0 -47
  526. package/docs/api/interfaces/UseResourcePermissionsOptions.md +0 -34
  527. package/docs/api/interfaces/UserEventAccess.md +0 -118
  528. package/docs/api/interfaces/UserMenuProps.md +0 -86
  529. package/docs/api/interfaces/UserProfile.md +0 -63
  530. package/docs/migration/quick-migration-guide.md +0 -356
  531. package/docs/migration/service-architecture.md +0 -281
  532. package/src/components/EventSelector/EventSelector.test.tsx +0 -720
  533. package/src/components/EventSelector/EventSelector.tsx +0 -420
  534. package/src/components/EventSelector/index.ts +0 -3
  535. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +0 -784
  536. package/src/components/OrganisationSelector/OrganisationSelector.tsx +0 -324
  537. package/src/components/OrganisationSelector/index.ts +0 -9
  538. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  539. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  540. package/src/hooks/useSecureDataAccess.ts +0 -681
  541. /package/dist/{DataTable-DQ7RSOHE.js.map → DataTable-THFPBKTP.js.map} +0 -0
  542. /package/dist/{UnifiedAuthProvider-ATAP5UTR.js.map → UnifiedAuthProvider-KAGUYQ4J.js.map} +0 -0
  543. /package/dist/{api-N774RPUA.js.map → api-IAGWF3ZG.js.map} +0 -0
  544. /package/dist/{audit-B5P6FFIR.js.map → audit-V53FV5AG.js.map} +0 -0
  545. /package/dist/{chunk-7D4SUZUM.js.map → chunk-DGUM43GV.js.map} +0 -0
  546. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  547. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  548. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  549. /package/docs/migration/{REACT_19_MIGRATION.md → V0.6.0_REACT_19_MIGRATION.md} +0 -0
@@ -378,6 +378,112 @@ module.exports = {
378
378
  }
379
379
  };
380
380
  }
381
+ },
382
+
383
+ /**
384
+ * Disallow direct Supabase client creation - must use useSecureSupabase
385
+ */
386
+ 'no-direct-supabase-client': {
387
+ meta: {
388
+ type: 'problem',
389
+ docs: {
390
+ description: 'Disallow direct createClient calls from @supabase/supabase-js. Use useSecureSupabase() from pace-core instead to ensure organisation context and RLS policies are enforced.',
391
+ category: 'Security',
392
+ recommended: true
393
+ },
394
+ messages: {
395
+ directClientCreation: "Direct Supabase client creation detected. You MUST use useSecureSupabase() from '@jmruthers/pace-core/rbac' instead to ensure organisation context and RLS policies are enforced. This prevents cross-organisation data access.",
396
+ directClientImport: "Direct import of createClient from @supabase/supabase-js is not allowed. Use useSecureSupabase() from '@jmruthers/pace-core/rbac' instead."
397
+ },
398
+ hasSuggestions: true
399
+ },
400
+ create(context) {
401
+ let hasSupabaseImport = false;
402
+ let createClientImported = false;
403
+ const filename = context.getFilename();
404
+
405
+ // Allow createClient in specific config files (supabaseClient.ts/js, etc.)
406
+ const isConfigFile = /(supabase|client)\.(ts|js|tsx|jsx)$/i.test(filename) &&
407
+ (filename.includes('supabase') || filename.includes('client'));
408
+
409
+ return {
410
+ ImportDeclaration(node) {
411
+ const importSource = node.source.value;
412
+
413
+ // Check for @supabase/supabase-js import
414
+ if (importSource === '@supabase/supabase-js') {
415
+ hasSupabaseImport = true;
416
+
417
+ // Check if createClient is imported
418
+ const hasCreateClient = node.specifiers.some(spec => {
419
+ if (spec.type === 'ImportSpecifier') {
420
+ return spec.imported.name === 'createClient';
421
+ }
422
+ if (spec.type === 'ImportNamespaceSpecifier') {
423
+ return true; // import * as supabase
424
+ }
425
+ return false;
426
+ });
427
+
428
+ if (hasCreateClient) {
429
+ createClientImported = true;
430
+
431
+ // Only report if not in a config file
432
+ if (!isConfigFile) {
433
+ context.report({
434
+ node: node.source,
435
+ messageId: 'directClientImport',
436
+ suggest: [{
437
+ desc: 'Replace with useSecureSupabase hook',
438
+ fix(fixer) {
439
+ // Remove the import
440
+ return fixer.remove(node);
441
+ }
442
+ }]
443
+ });
444
+ }
445
+ }
446
+ }
447
+ },
448
+
449
+ CallExpression(node) {
450
+ // Check for createClient() calls
451
+ if (node.callee.type === 'Identifier' && node.callee.name === 'createClient') {
452
+ // Only report if not in a config file
453
+ if (!isConfigFile) {
454
+ context.report({
455
+ node,
456
+ messageId: 'directClientCreation',
457
+ suggest: [{
458
+ desc: 'Use useSecureSupabase() hook instead',
459
+ fix(fixer) {
460
+ // This is complex to auto-fix, so we'll just report
461
+ return null;
462
+ }
463
+ }]
464
+ });
465
+ }
466
+ }
467
+
468
+ // Check for supabase.createClient() or similar patterns
469
+ if (node.callee.type === 'MemberExpression' &&
470
+ node.callee.property?.name === 'createClient') {
471
+ if (!isConfigFile) {
472
+ context.report({
473
+ node,
474
+ messageId: 'directClientCreation',
475
+ suggest: [{
476
+ desc: 'Use useSecureSupabase() hook instead',
477
+ fix(fixer) {
478
+ return null;
479
+ }
480
+ }]
481
+ });
482
+ }
483
+ }
484
+ }
485
+ };
486
+ }
381
487
  }
382
488
  }
383
489
  };
@@ -64,10 +64,7 @@ describe('hooks index exports', () => {
64
64
  expect(typeof Hooks.useOrganisationPermissions).toBe('function');
65
65
  });
66
66
 
67
- it('should export useSecureDataAccess', () => {
68
- expect(Hooks).toHaveProperty('useSecureDataAccess');
69
- expect(typeof Hooks.useSecureDataAccess).toBe('function');
70
- });
67
+ // useSecureDataAccess has been removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
71
68
 
72
69
  it('should export useOrganisationSecurity', () => {
73
70
  expect(Hooks).toHaveProperty('useOrganisationSecurity');
@@ -190,7 +187,7 @@ describe('hooks index exports', () => {
190
187
  'useDebounce',
191
188
  'useDataTableState',
192
189
  'useOrganisationPermissions',
193
- 'useSecureDataAccess',
190
+ // 'useSecureDataAccess', // Removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
194
191
  'useOrganisationSecurity',
195
192
  'useZodForm',
196
193
  'useComponentPerformance',
@@ -99,7 +99,7 @@ describe('useAppConfig Hook', () => {
99
99
  vi.restoreAllMocks();
100
100
  });
101
101
 
102
- describe('Public Page Context', () => {
102
+ describe('Public Page Context', () => {
103
103
  beforeEach(() => {
104
104
  mockUseIsPublicPage.mockReturnValue(true);
105
105
  });
@@ -107,8 +107,6 @@ describe('useAppConfig Hook', () => {
107
107
  it('should return public page configuration when in public context', () => {
108
108
  const { result } = renderHook(() => useAppConfig());
109
109
 
110
- expect(result.current.supportsDirectAccess).toBe(false);
111
- expect(result.current.requiresEvent).toBe(true);
112
110
  expect(result.current.isLoading).toBe(false);
113
111
  // Note: If VITE_APP_NAME is set in .env (e.g., CORE), the hook will use it.
114
112
  // Otherwise, it defaults to 'PACE'. This test verifies it returns a valid string.
@@ -122,8 +120,6 @@ describe('useAppConfig Hook', () => {
122
120
  const { result } = renderHook(() => useAppConfig());
123
121
 
124
122
  // Public pages should always have these characteristics
125
- expect(result.current.supportsDirectAccess).toBe(false);
126
- expect(result.current.requiresEvent).toBe(true);
127
123
  expect(result.current.isLoading).toBe(false);
128
124
  expect(typeof result.current.appName).toBe('string');
129
125
  });
@@ -134,80 +130,23 @@ describe('useAppConfig Hook', () => {
134
130
  mockUseIsPublicPage.mockReturnValue(false);
135
131
  // Set default mock for useUnifiedAuth
136
132
  mockUseUnifiedAuthFn.mockReturnValue({
137
- appConfig: { requires_event: true },
138
133
  appName: 'PACE',
139
134
  } as any);
140
135
  });
141
136
 
142
137
  it('should return configuration from UnifiedAuthProvider when available', () => {
143
- const mockAppConfig = {
144
- requires_event: false,
145
- };
146
138
  const mockAppName = 'AuthApp';
147
139
 
148
140
  mockUseUnifiedAuthFn.mockReturnValue({
149
- appConfig: mockAppConfig,
150
141
  appName: mockAppName,
151
142
  } as any);
152
143
 
153
144
  const { result } = renderHook(() => useAppConfig());
154
145
 
155
- expect(result.current.supportsDirectAccess).toBe(true);
156
- expect(result.current.requiresEvent).toBe(false);
157
146
  expect(result.current.isLoading).toBe(false);
158
147
  expect(result.current.appName).toBe('AuthApp');
159
148
  });
160
149
 
161
- it('should handle requires_event: true', () => {
162
- const mockAppConfig = {
163
- requires_event: true,
164
- };
165
- const mockAppName = 'EventApp';
166
-
167
- mockUseUnifiedAuthFn.mockReturnValue({
168
- appConfig: mockAppConfig,
169
- appName: mockAppName,
170
- } as any);
171
-
172
- const { result } = renderHook(() => useAppConfig());
173
-
174
- expect(result.current.supportsDirectAccess).toBe(false);
175
- expect(result.current.requiresEvent).toBe(true);
176
- expect(result.current.isLoading).toBe(false);
177
- expect(result.current.appName).toBe('EventApp');
178
- });
179
-
180
- it('should handle null appConfig (loading state)', () => {
181
- mockUseUnifiedAuthFn.mockReturnValue({
182
- appConfig: null,
183
- appName: 'LoadingApp',
184
- } as any);
185
-
186
- const { result } = renderHook(() => useAppConfig());
187
-
188
- expect(result.current.supportsDirectAccess).toBe(false);
189
- expect(result.current.requiresEvent).toBe(true);
190
- expect(result.current.isLoading).toBe(true);
191
- expect(result.current.appName).toBe('LoadingApp');
192
- });
193
-
194
- it('should handle undefined appConfig.requires_event', () => {
195
- const mockAppConfig = {};
196
- const mockAppName = 'DefaultApp';
197
-
198
- mockUseUnifiedAuthFn.mockReturnValue({
199
- appConfig: mockAppConfig,
200
- appName: mockAppName,
201
- } as any);
202
-
203
- const { result } = renderHook(() => useAppConfig());
204
-
205
- expect(result.current.supportsDirectAccess).toBe(false);
206
- expect(result.current.requiresEvent).toBe(true);
207
- expect(result.current.isLoading).toBe(false);
208
- expect(result.current.appName).toBe('DefaultApp');
209
- });
210
-
211
150
  it('should handle UnifiedAuthProvider error and return fallback', () => {
212
151
  mockUseUnifiedAuthFn.mockImplementation(() => {
213
152
  throw new Error('Provider not available');
@@ -215,8 +154,6 @@ describe('useAppConfig Hook', () => {
215
154
 
216
155
  const { result } = renderHook(() => useAppConfig());
217
156
 
218
- expect(result.current.supportsDirectAccess).toBe(false);
219
- expect(result.current.requiresEvent).toBe(true);
220
157
  expect(result.current.isLoading).toBe(false);
221
158
  expect(result.current.appName).toBe('PACE');
222
159
  });
@@ -228,8 +165,6 @@ describe('useAppConfig Hook', () => {
228
165
 
229
166
  const { result } = renderHook(() => useAppConfig());
230
167
 
231
- expect(result.current.supportsDirectAccess).toBe(false);
232
- expect(result.current.requiresEvent).toBe(true);
233
168
  expect(result.current.isLoading).toBe(false);
234
169
  expect(result.current.appName).toBe('PACE');
235
170
  });
@@ -241,8 +176,6 @@ describe('useAppConfig Hook', () => {
241
176
 
242
177
  const { result } = renderHook(() => useAppConfig());
243
178
 
244
- expect(result.current.supportsDirectAccess).toBe(false);
245
- expect(result.current.requiresEvent).toBe(true);
246
179
  expect(result.current.isLoading).toBe(false);
247
180
  expect(result.current.appName).toBe('PACE');
248
181
  });
@@ -264,11 +197,9 @@ describe('useAppConfig Hook', () => {
264
197
  it('should memoize authenticated configuration based on dependencies', () => {
265
198
  mockUseIsPublicPage.mockReturnValue(false);
266
199
 
267
- const mockAppConfig = { requires_event: false };
268
200
  const mockAppName = 'TestApp';
269
201
 
270
202
  mockUseUnifiedAuthFn.mockReturnValue({
271
- appConfig: mockAppConfig,
272
203
  appName: mockAppName,
273
204
  } as any);
274
205
 
@@ -281,25 +212,21 @@ describe('useAppConfig Hook', () => {
281
212
 
282
213
  expect(result.current).toBe(firstResult);
283
214
 
284
- // Rerender with different appConfig
215
+ // Rerender with different appName
285
216
  mockUseUnifiedAuthFn.mockReturnValue({
286
- appConfig: { requires_event: true },
287
- appName: mockAppName,
217
+ appName: 'DifferentApp',
288
218
  } as any);
289
219
 
290
220
  rerender();
291
221
 
292
222
  expect(result.current).not.toBe(firstResult);
293
- expect(result.current.requiresEvent).toBe(true);
223
+ expect(result.current.appName).toBe('DifferentApp');
294
224
  });
295
225
 
296
226
  it('should memoize authenticated configuration based on appName changes', () => {
297
227
  mockUseIsPublicPage.mockReturnValue(false);
298
228
 
299
- const mockAppConfig = { requires_event: false };
300
-
301
229
  mockUseUnifiedAuthFn.mockReturnValue({
302
- appConfig: mockAppConfig,
303
230
  appName: 'App1',
304
231
  } as any);
305
232
 
@@ -309,7 +236,6 @@ describe('useAppConfig Hook', () => {
309
236
 
310
237
  // Rerender with different appName
311
238
  mockUseUnifiedAuthFn.mockReturnValue({
312
- appConfig: mockAppConfig,
313
239
  appName: 'App2',
314
240
  } as any);
315
241
 
@@ -327,7 +253,6 @@ describe('useAppConfig Hook', () => {
327
253
 
328
254
  const { result: publicResult } = renderHook(() => useAppConfig());
329
255
 
330
- expect(publicResult.current.supportsDirectAccess).toBe(false);
331
256
  // Note: App name depends on environment - may be 'PACE' (default) or 'CORE' (from .env)
332
257
  expect(typeof publicResult.current.appName).toBe('string');
333
258
  expect(['PACE', 'CORE']).toContain(publicResult.current.appName);
@@ -335,13 +260,11 @@ describe('useAppConfig Hook', () => {
335
260
  // Test authenticated page context separately
336
261
  mockUseIsPublicPage.mockReturnValue(false);
337
262
  mockUseUnifiedAuthFn.mockReturnValue({
338
- appConfig: { requires_event: false },
339
263
  appName: 'AuthApp',
340
264
  } as any);
341
265
 
342
266
  const { result: authResult } = renderHook(() => useAppConfig());
343
267
 
344
- expect(authResult.current.supportsDirectAccess).toBe(true);
345
268
  expect(authResult.current.appName).toBe('AuthApp');
346
269
  });
347
270
  });
@@ -350,30 +273,13 @@ describe('useAppConfig Hook', () => {
350
273
  it('should return correct types for all return values', () => {
351
274
  mockUseIsPublicPage.mockReturnValue(false);
352
275
  mockUseUnifiedAuthFn.mockReturnValue({
353
- appConfig: { requires_event: false },
354
276
  appName: 'TypeTestApp',
355
277
  } as any);
356
278
 
357
279
  const { result } = renderHook(() => useAppConfig());
358
280
 
359
- expect(typeof result.current.supportsDirectAccess).toBe('boolean');
360
- expect(typeof result.current.requiresEvent).toBe('boolean');
361
281
  expect(typeof result.current.isLoading).toBe('boolean');
362
282
  expect(typeof result.current.appName).toBe('string');
363
283
  });
364
-
365
- it('should handle malformed appConfig objects', () => {
366
- mockUseIsPublicPage.mockReturnValue(false);
367
- mockUseUnifiedAuthFn.mockReturnValue({
368
- appConfig: { requires_event: 'not-a-boolean' },
369
- appName: 'MalformedApp',
370
- } as any);
371
-
372
- const { result } = renderHook(() => useAppConfig());
373
-
374
- // The hook uses the value directly, so it will be truthy
375
- expect(result.current.requiresEvent).toBe('not-a-boolean');
376
- expect(result.current.supportsDirectAccess).toBe(false);
377
- });
378
284
  });
379
285
  });
@@ -33,9 +33,8 @@ export type { UseAddressAutocompleteOptions, UseAddressAutocompleteReturn } from
33
33
 
34
34
  // === ORGANISATION HOOKS ===
35
35
  export { useOrganisationPermissions } from './useOrganisationPermissions';
36
- export { useSecureDataAccess } from './useSecureDataAccess';
36
+ // useSecureDataAccess has been removed - use useSecureSupabase from @jmruthers/pace-core/rbac instead
37
37
  export type { UseOrganisationPermissionsReturn } from './useOrganisationPermissions';
38
- export type { SecureDataAccessReturn } from './useSecureDataAccess';
39
38
  export { useOrganisationSecurity } from './useOrganisationSecurity';
40
39
  export type { OrganisationSecurityHook } from './useOrganisationSecurity';
41
40
 
@@ -70,6 +70,10 @@ import { logger } from '../../utils/core/logger';
70
70
  // Simple in-memory cache for public data
71
71
  const publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
72
72
 
73
+ /**
74
+ * Return value of the usePublicEvent hook.
75
+ * Provides event data, loading state, error, and refetch function.
76
+ */
73
77
  export interface UsePublicEventReturn {
74
78
  /** The event data, null if not loaded or not found */
75
79
  event: Event | null;
@@ -74,6 +74,10 @@ const log = createLogger('usePublicEventLogo');
74
74
  // Simple in-memory cache for public data
75
75
  const publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
76
76
 
77
+ /**
78
+ * Return value of the usePublicEventLogo hook.
79
+ * Provides logo URL, fallback text, loading state, error, and refetch function.
80
+ */
77
81
  export interface UsePublicEventLogoReturn {
78
82
  /** The logo URL if available, null if not found or error */
79
83
  logoUrl: string | null;
@@ -46,6 +46,10 @@ import { logger } from '../../utils/core/logger';
46
46
  // Simple in-memory cache for public file data
47
47
  const publicFileCache = new Map<string, { data: any; timestamp: number; ttl: number }>();
48
48
 
49
+ /**
50
+ * Return value of the usePublicFileDisplay hook.
51
+ * Provides file URLs, references, loading state, error, and refetch function.
52
+ */
49
53
  export interface UsePublicFileDisplayReturn {
50
54
  /** Single file URL if category is provided and file found, null otherwise */
51
55
  fileUrl: string | null;
@@ -61,6 +61,10 @@ import { useParams, useLocation } from 'react-router-dom';
61
61
  import type { Event } from '../../types/event';
62
62
  import { usePublicEvent } from './usePublicEvent';
63
63
 
64
+ /**
65
+ * Return value of the usePublicRouteParams hook.
66
+ * Provides event code, event ID, event data, loading state, error, and refetch function.
67
+ */
64
68
  export interface UsePublicRouteParamsReturn {
65
69
  /** The event code from the URL */
66
70
  eventCode: string | null;
@@ -11,23 +11,55 @@
11
11
  import { useAuthService } from './useAuthService';
12
12
  import { type User, type Session, type SupabaseClient, AuthError } from '@supabase/supabase-js';
13
13
 
14
+ /**
15
+ * Authentication state and methods returned by the useAuth hook.
16
+ */
14
17
  export interface AuthState {
18
+ /** Current authenticated user, or null if not authenticated */
15
19
  user: User | null;
20
+ /** Current session, or null if not authenticated */
16
21
  session: Session | null;
22
+ /** Whether the user is currently authenticated */
17
23
  isAuthenticated: boolean;
24
+ /** Whether authentication state is currently loading */
18
25
  authLoading: boolean;
26
+ /** Any authentication error that occurred, or null */
19
27
  authError: AuthError | null;
28
+ /** Supabase client instance, or null if not available */
20
29
  supabase: SupabaseClient | null;
21
30
 
22
31
  // Auth methods
32
+ /** Sign in with email and optional password */
23
33
  signIn: (email: string, password?: string) => Promise<{ error: AuthError | null }>;
34
+ /** Sign up with email and password */
24
35
  signUp: (email: string, password: string) => Promise<{ error: AuthError | null }>;
36
+ /** Sign out the current user */
25
37
  signOut: () => Promise<{ error: AuthError | null }>;
38
+ /** Request a password reset email */
26
39
  resetPassword: (email: string) => Promise<{ error: AuthError | null }>;
40
+ /** Update the current user's password */
27
41
  updatePassword: (password: string) => Promise<{ error: AuthError | null }>;
42
+ /** Refresh the current session */
28
43
  refreshSession: () => Promise<{ error: AuthError | null }>;
29
44
  }
30
45
 
46
+ /**
47
+ * Convenience hook for authentication.
48
+ * Returns the auth state and methods needed by components.
49
+ *
50
+ * @returns Authentication state and methods
51
+ *
52
+ * @example
53
+ * ```tsx
54
+ * const { user, isAuthenticated, signIn, signOut } = useAuth();
55
+ *
56
+ * if (!isAuthenticated) {
57
+ * return <LoginForm onSignIn={signIn} />;
58
+ * }
59
+ *
60
+ * return <Dashboard user={user} onSignOut={signOut} />;
61
+ * ```
62
+ */
31
63
  export function useAuth(): AuthState {
32
64
  const authService = useAuthService();
33
65
 
@@ -22,6 +22,12 @@ export interface CurrentEventState {
22
22
  refreshEvents: () => Promise<void>;
23
23
  }
24
24
 
25
+ /**
26
+ * Convenience hook for accessing current event state.
27
+ * Returns event state and methods needed by components.
28
+ *
29
+ * @returns Current event state including events, selected event, loading state, and methods
30
+ */
25
31
  export function useCurrentEvent(): CurrentEventState {
26
32
  const eventService = useEventService();
27
33
 
@@ -30,6 +30,12 @@ export interface CurrentOrganisationState {
30
30
  getPrimaryOrganisation: () => Organisation | null;
31
31
  }
32
32
 
33
+ /**
34
+ * Convenience hook for accessing current organisation state.
35
+ * Returns organisation state and methods needed by components.
36
+ *
37
+ * @returns Current organisation state including selected organisation, organisations, memberships, and methods
38
+ */
33
39
  export function useCurrentOrganisation(): CurrentOrganisationState {
34
40
  const organisationService = useOrganisationService();
35
41
 
@@ -4,26 +4,19 @@
4
4
  * @module Hooks/useAppConfig
5
5
  * @since 0.4.0
6
6
  *
7
- * Hook for accessing app configuration like direct access support and event requirements.
8
- * This is a convenience hook that extracts app config from the UnifiedAuthProvider.
7
+ * Hook for accessing app name and loading state.
8
+ *
9
+ * NOTE: Scope configuration (requires_event) is now page-level only (rbac_app_pages.scope_type).
10
+ * Use getPageScopeType() to determine if a specific page requires event or organisation context.
9
11
  *
10
12
  * @example
11
13
  * ```tsx
12
14
  * function MyComponent() {
13
- * const { supportsDirectAccess, requiresEvent, isLoading } = useAppConfig();
15
+ * const { appName, isLoading } = useAppConfig();
14
16
  *
15
17
  * if (isLoading) return <div>Loading...</div>;
16
18
  *
17
- * return (
18
- * <div>
19
- * {supportsDirectAccess && (
20
- * <div>This app supports direct access!</div>
21
- * )}
22
- * {requiresEvent && (
23
- * <EventSelector />
24
- * )}
25
- * </div>
26
- * );
19
+ * return <div>App: {appName}</div>;
27
20
  * }
28
21
  * ```
29
22
  */
@@ -33,10 +26,8 @@ import { useUnifiedAuth } from '../providers/services/UnifiedAuthProvider';
33
26
  import { useIsPublicPage, PublicPageContext } from '../components/PublicLayout/PublicPageProvider';
34
27
 
35
28
  export interface UseAppConfigReturn {
36
- supportsDirectAccess: boolean;
37
- requiresEvent: boolean;
38
- isLoading: boolean;
39
29
  appName: string;
30
+ isLoading: boolean;
40
31
  }
41
32
 
42
33
  /**
@@ -92,32 +83,26 @@ export function useAppConfig(): UseAppConfigReturn {
92
83
  };
93
84
 
94
85
  return useMemo(() => ({
95
- supportsDirectAccess: false, // Public pages don't support direct access
96
- requiresEvent: true, // Public pages always require an event
97
- isLoading: false,
98
- appName: getAppName()
86
+ appName: getAppName(),
87
+ isLoading: false
99
88
  }), [contextAppName, hasPublicContext]);
100
89
  }
101
90
 
102
91
  // For authenticated pages, use UnifiedAuthProvider
103
92
  try {
104
- const { appConfig, appName } = useUnifiedAuth();
93
+ const { appName } = useUnifiedAuth();
105
94
  return useMemo(() => ({
106
- supportsDirectAccess: !(appConfig?.requires_event ?? true),
107
- requiresEvent: appConfig?.requires_event ?? true,
108
- isLoading: appConfig === null,
109
- appName
110
- }), [appConfig?.requires_event, appName]);
95
+ appName,
96
+ isLoading: false
97
+ }), [appName]);
111
98
  } catch (error) {
112
99
  // Fallback if UnifiedAuthProvider is not available
113
100
  return useMemo(() => ({
114
- supportsDirectAccess: false,
115
- requiresEvent: true,
116
- isLoading: false,
117
101
  appName: contextAppName ||
118
102
  getNodeEnvVar('VITE_APP_NAME') ||
119
103
  getNodeEnvVar('NEXT_PUBLIC_APP_NAME') ||
120
- 'PACE'
104
+ 'PACE',
105
+ isLoading: false
121
106
  }), [contextAppName]);
122
107
  }
123
108
  }
@@ -1,6 +1,15 @@
1
1
 
2
2
  import { useState, useEffect } from 'react';
3
3
 
4
+ /**
5
+ * Hook for debouncing a value.
6
+ * Returns a debounced version of the value that only updates after the specified delay.
7
+ *
8
+ * @template T - The type of the value to debounce
9
+ * @param value - The value to debounce
10
+ * @param delay - The delay in milliseconds
11
+ * @returns The debounced value
12
+ */
4
13
  export function useDebounce<T>(value: T, delay: number): T {
5
14
  const [debouncedValue, setDebouncedValue] = useState<T>(value);
6
15
 
@@ -92,6 +92,12 @@ const log = createLogger('useEventTheme');
92
92
  * }
93
93
  * ```
94
94
  */
95
+ /**
96
+ * Hook that automatically applies event-specific theming.
97
+ * Works in authenticated mode (via EventProvider) or public page mode (via event prop).
98
+ *
99
+ * @param event - Optional event object for public page mode. If not provided, uses EventProvider context.
100
+ */
95
101
  export function useEventTheme(event?: Event | null): void {
96
102
  const location = useLocation();
97
103