@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
@@ -1,680 +0,0 @@
1
- import { renderHook, act } from '@testing-library/react';
2
- import { vi, describe, it, expect, beforeEach } from 'vitest';
3
- import { useSecureDataAccess } from '../useSecureDataAccess';
4
- import { useUnifiedAuth } from '../../providers';
5
- import { useOrganisations } from '../../hooks/useOrganisations';
6
- import { testDataGenerators } from '../../__tests__/helpers/test-utils';
7
- import { useResolvedScope } from '../../rbac/hooks/useResolvedScope';
8
- import { useOrganisationSecurity } from '../useOrganisationSecurity';
9
-
10
- // Mock dependencies
11
- vi.mock('../../providers', () => ({
12
- useUnifiedAuth: vi.fn(),
13
- }));
14
-
15
- vi.mock('../../providers/services/UnifiedAuthProvider', () => ({
16
- useUnifiedAuth: vi.fn(),
17
- }));
18
-
19
- vi.mock('../../hooks/useOrganisations', () => ({
20
- useOrganisations: vi.fn(),
21
- }));
22
-
23
- vi.mock('../../utils/context/organisationContext', () => ({
24
- setOrganisationContext: vi.fn().mockResolvedValue(undefined),
25
- }));
26
-
27
- vi.mock('../../rbac/hooks/useResolvedScope', () => ({
28
- useResolvedScope: vi.fn(),
29
- }));
30
-
31
- vi.mock('../useOrganisationSecurity', () => ({
32
- useOrganisationSecurity: vi.fn(),
33
- }));
34
-
35
- const mockUseUnifiedAuth = {
36
- user: null,
37
- session: null,
38
- supabase: null,
39
- selectedOrganisation: null,
40
- selectedEvent: null,
41
- };
42
-
43
- const mockUseOrganisations = vi.fn(() => ({
44
- selectedOrganisation: null,
45
- organisations: [],
46
- userMemberships: [],
47
- isLoading: false,
48
- error: null,
49
- hasValidOrganisationContext: false,
50
- isContextReady: false,
51
- switchOrganisation: vi.fn(),
52
- getUserRole: vi.fn(),
53
- validateOrganisationAccess: vi.fn(),
54
- refreshOrganisations: vi.fn(),
55
- ensureOrganisationContext: vi.fn(),
56
- isOrganisationSecure: vi.fn(),
57
- getPrimaryOrganisation: vi.fn(),
58
- }));
59
-
60
- // Helper function to create authenticated context
61
- const createAuthenticatedContext = (supabase = { auth: {} }, org = { id: 'org-123' }) => {
62
- const mockUser = testDataGenerators.createUser(1, { id: 'user-123' });
63
- const mockSession = testDataGenerators.createSession(1, { access_token: 'test-token' });
64
-
65
- vi.mocked(useUnifiedAuth).mockReturnValue({
66
- ...mockUseUnifiedAuth,
67
- user: mockUser,
68
- session: mockSession,
69
- supabase,
70
- selectedOrganisation: org,
71
- } as any);
72
-
73
- // Create a fresh mock with ensureOrganisationContext that returns the org
74
- const mockOrgs = {
75
- selectedOrganisation: null,
76
- organisations: [],
77
- userMemberships: [],
78
- isLoading: false,
79
- error: null,
80
- hasValidOrganisationContext: false,
81
- isContextReady: false,
82
- switchOrganisation: vi.fn(),
83
- getUserRole: vi.fn(),
84
- validateOrganisationAccess: vi.fn(),
85
- refreshOrganisations: vi.fn(),
86
- ensureOrganisationContext: vi.fn().mockReturnValue(org),
87
- isOrganisationSecure: vi.fn(),
88
- getPrimaryOrganisation: vi.fn(),
89
- };
90
-
91
- vi.mocked(useOrganisations).mockReturnValue(mockOrgs as any);
92
-
93
- // Mock resolved scope with organisationId
94
- vi.mocked(useResolvedScope).mockReturnValue({
95
- resolvedScope: {
96
- organisationId: org.id,
97
- eventId: undefined,
98
- appId: undefined,
99
- },
100
- isLoading: false,
101
- error: null,
102
- });
103
- };
104
-
105
- describe('useSecureDataAccess', () => {
106
- beforeEach(() => {
107
- vi.clearAllMocks();
108
- vi.mocked(useUnifiedAuth).mockReturnValue(mockUseUnifiedAuth as any);
109
- // Set up useOrganisations to return the default mock (which throws for org context)
110
- vi.mocked(useOrganisations).mockReturnValue(mockUseOrganisations() as any);
111
- // Default mock for useResolvedScope - returns null scope (no context)
112
- vi.mocked(useResolvedScope).mockReturnValue({
113
- resolvedScope: null,
114
- isLoading: false,
115
- error: null,
116
- });
117
- // Default mock for useOrganisationSecurity - not super admin
118
- vi.mocked(useOrganisationSecurity).mockReturnValue({
119
- superAdminContext: { isSuperAdmin: false, hasGlobalAccess: false, canManageAllOrganisations: false },
120
- validateOrganisationAccess: vi.fn(),
121
- hasMinimumRole: vi.fn(),
122
- canAccessChildOrganisations: vi.fn(),
123
- checkPermission: vi.fn(),
124
- getPermissions: vi.fn(),
125
- logOrganisationAccess: vi.fn(),
126
- canManageOrganisation: vi.fn(),
127
- } as any);
128
- });
129
-
130
- describe('validateContext', () => {
131
- it('should throw error when no supabase client', () => {
132
- const { result } = renderHook(() => useSecureDataAccess());
133
-
134
- expect(() => result.current.validateContext()).toThrow('No Supabase client available');
135
- });
136
-
137
- it('should throw error when no organisation context', () => {
138
- const mockSupabase = { auth: {} };
139
- const mockUser = testDataGenerators.createUser(1, { id: 'user-123' });
140
- const mockSession = testDataGenerators.createSession(1, { access_token: 'test-token' });
141
-
142
- vi.mocked(useUnifiedAuth).mockReturnValue({
143
- ...mockUseUnifiedAuth,
144
- supabase: mockSupabase,
145
- user: mockUser,
146
- session: mockSession,
147
- } as any);
148
-
149
- // Create a mock that throws
150
- const mockOrgsThrowing = {
151
- ...mockUseOrganisations(),
152
- ensureOrganisationContext: vi.fn().mockImplementation(() => {
153
- throw new Error('Organisation context is required');
154
- }),
155
- };
156
- vi.mocked(useOrganisations).mockReturnValue(mockOrgsThrowing as any);
157
-
158
- const { result } = renderHook(() => useSecureDataAccess());
159
-
160
- expect(() => result.current.validateContext()).toThrow('Organisation context is required');
161
- });
162
-
163
- it('should not throw when context is valid', () => {
164
- const mockSupabase = { auth: {} };
165
- const mockUser = testDataGenerators.createUser(1, { id: 'user-123' });
166
- const mockSession = testDataGenerators.createSession(1, { access_token: 'test-token' });
167
-
168
- vi.mocked(useUnifiedAuth).mockReturnValue({
169
- ...mockUseUnifiedAuth,
170
- user: mockUser,
171
- session: mockSession,
172
- supabase: mockSupabase,
173
- selectedOrganisation: { id: 'org-123' },
174
- } as any);
175
-
176
- // Mock useResolvedScope to return resolved scope with organisationId
177
- vi.mocked(useResolvedScope).mockReturnValue({
178
- resolvedScope: {
179
- organisationId: 'org-123',
180
- eventId: undefined,
181
- appId: undefined,
182
- },
183
- isLoading: false,
184
- error: null,
185
- });
186
-
187
- const { result } = renderHook(() => useSecureDataAccess());
188
-
189
- expect(() => result.current.validateContext()).not.toThrow();
190
- });
191
- });
192
-
193
- describe('getCurrentOrganisationId', () => {
194
- it('should return organisation ID when context is valid', () => {
195
- const mockSupabase = { auth: {} };
196
- const mockUser = testDataGenerators.createUser(1, { id: 'user-123' });
197
- const mockSession = testDataGenerators.createSession(1, { access_token: 'test-token' });
198
-
199
- vi.mocked(useUnifiedAuth).mockReturnValue({
200
- ...mockUseUnifiedAuth,
201
- user: mockUser,
202
- session: mockSession,
203
- supabase: mockSupabase,
204
- selectedOrganisation: { id: 'org-123' },
205
- } as any);
206
-
207
- // Mock resolved scope with organisationId
208
- vi.mocked(useResolvedScope).mockReturnValue({
209
- resolvedScope: {
210
- organisationId: 'org-123',
211
- eventId: undefined,
212
- appId: undefined,
213
- },
214
- isLoading: false,
215
- error: null,
216
- });
217
-
218
- const { result } = renderHook(() => useSecureDataAccess());
219
-
220
- expect(result.current.getCurrentOrganisationId()).toBe('org-123');
221
- });
222
-
223
- it('should throw error when context is invalid', () => {
224
- const mockSupabase = { auth: {} };
225
- vi.mocked(useUnifiedAuth).mockReturnValue({
226
- ...mockUseUnifiedAuth,
227
- supabase: mockSupabase
228
- } as any);
229
-
230
- const mockOrgsThrowing = {
231
- ...mockUseOrganisations(),
232
- ensureOrganisationContext: vi.fn().mockImplementation(() => {
233
- throw new Error('Organisation context is required');
234
- }),
235
- };
236
- vi.mocked(useOrganisations).mockReturnValue(mockOrgsThrowing as any);
237
-
238
- const { result } = renderHook(() => useSecureDataAccess());
239
-
240
- expect(() => result.current.getCurrentOrganisationId()).toThrow('User must be authenticated with valid session');
241
- });
242
- });
243
-
244
- describe('secureQuery', () => {
245
- it('should execute query with organisation filter', async () => {
246
- // Create a mock that returns a promise when awaited
247
- const mockQuery = {
248
- eq: vi.fn().mockReturnThis(),
249
- order: vi.fn().mockReturnThis(),
250
- limit: vi.fn().mockReturnThis(),
251
- range: vi.fn().mockReturnThis()
252
- };
253
-
254
- // Create a promise that resolves to the expected data
255
- const mockPromise = Promise.resolve({ data: [{ id: 1, name: 'Test' }], error: null });
256
-
257
- // Make the mock query chain behave like a promise
258
- Object.defineProperty(mockQuery, 'then', {
259
- value: mockPromise.then.bind(mockPromise),
260
- writable: true,
261
- configurable: true
262
- });
263
-
264
- const mockSupabase = {
265
- from: vi.fn().mockReturnValue({
266
- select: vi.fn().mockReturnValue(mockQuery)
267
- })
268
- };
269
-
270
- createAuthenticatedContext(mockSupabase);
271
-
272
- const { result } = renderHook(() => useSecureDataAccess());
273
-
274
- const data = await result.current.secureQuery('test_table', '*');
275
-
276
- expect(data).toEqual([{ id: 1, name: 'Test' }]);
277
- expect(mockSupabase.from).toHaveBeenCalledWith('test_table');
278
- });
279
-
280
- it('should handle query errors', async () => {
281
- // Create a mock that returns a promise with an error
282
- const mockQuery = {
283
- eq: vi.fn().mockReturnThis(),
284
- order: vi.fn().mockReturnThis(),
285
- limit: vi.fn().mockReturnThis(),
286
- range: vi.fn().mockReturnThis()
287
- };
288
-
289
- // Create a promise that resolves to an error
290
- const mockPromise = Promise.resolve({ data: null, error: new Error('Query failed') });
291
-
292
- // Make the mock query chain behave like a promise
293
- Object.defineProperty(mockQuery, 'then', {
294
- value: mockPromise.then.bind(mockPromise),
295
- writable: true,
296
- configurable: true
297
- });
298
-
299
- const mockSupabase = {
300
- from: vi.fn().mockReturnValue({
301
- select: vi.fn().mockReturnValue(mockQuery)
302
- })
303
- };
304
-
305
- createAuthenticatedContext(mockSupabase);
306
-
307
- const { result } = renderHook(() => useSecureDataAccess());
308
-
309
- await expect(result.current.secureQuery('test_table', '*')).rejects.toThrow('Query failed');
310
- });
311
-
312
- it('should handle null/undefined filter values', async () => {
313
- const mockSupabase = {
314
- from: vi.fn().mockReturnValue({
315
- select: vi.fn().mockReturnValue({
316
- eq: vi.fn().mockReturnValue({
317
- eq: vi.fn().mockResolvedValue({ data: [], error: null })
318
- })
319
- })
320
- })
321
- };
322
-
323
- createAuthenticatedContext(mockSupabase);
324
-
325
- const { result } = renderHook(() => useSecureDataAccess());
326
-
327
- const data = await result.current.secureQuery('test_table', '*', {
328
- status: 'active',
329
- category: null,
330
- type: undefined
331
- });
332
-
333
- expect(data).toEqual([]);
334
- });
335
-
336
- it('should return empty array when no data', async () => {
337
- const mockSupabase = {
338
- from: vi.fn().mockReturnValue({
339
- select: vi.fn().mockReturnValue({
340
- eq: vi.fn().mockResolvedValue({ data: null, error: null })
341
- })
342
- })
343
- };
344
- createAuthenticatedContext(mockSupabase);
345
-
346
- const { result } = renderHook(() => useSecureDataAccess());
347
-
348
- const data = await result.current.secureQuery('test_table', '*');
349
-
350
- expect(data).toEqual([]);
351
- });
352
- });
353
-
354
- describe('secureInsert', () => {
355
- it('should insert data with organisation ID', async () => {
356
- const mockSupabase = {
357
- from: vi.fn().mockReturnValue({
358
- insert: vi.fn().mockReturnValue({
359
- select: vi.fn().mockReturnValue({
360
- single: vi.fn().mockResolvedValue({ data: { id: 1, name: 'Test', organisation_id: 'org-123' }, error: null })
361
- })
362
- })
363
- })
364
- };
365
- createAuthenticatedContext(mockSupabase);
366
-
367
- const { result } = renderHook(() => useSecureDataAccess());
368
-
369
- const data = await result.current.secureInsert('test_table', { name: 'Test' });
370
-
371
- expect(data).toEqual({ id: 1, name: 'Test', organisation_id: 'org-123' });
372
- expect(mockSupabase.from).toHaveBeenCalledWith('test_table');
373
- });
374
-
375
- it('should handle insert errors', async () => {
376
- const mockSupabase = {
377
- from: vi.fn().mockReturnValue({
378
- insert: vi.fn().mockReturnValue({
379
- select: vi.fn().mockReturnValue({
380
- single: vi.fn().mockResolvedValue({ data: null, error: new Error('Insert failed') })
381
- })
382
- })
383
- })
384
- };
385
- createAuthenticatedContext(mockSupabase);
386
-
387
- const { result } = renderHook(() => useSecureDataAccess());
388
-
389
- await expect(result.current.secureInsert('test_table', { name: 'Test' })).rejects.toThrow('Insert failed');
390
- });
391
- });
392
-
393
- describe('secureUpdate', () => {
394
- it('should update data with organisation filter', async () => {
395
- const mockSupabase = {
396
- from: vi.fn().mockReturnValue({
397
- update: vi.fn().mockReturnValue({
398
- eq: vi.fn().mockReturnValue({
399
- eq: vi.fn().mockReturnValue({
400
- select: vi.fn().mockResolvedValue({ data: [{ id: 1, name: 'Updated', organisation_id: 'org-123' }], error: null })
401
- })
402
- })
403
- })
404
- })
405
- };
406
- createAuthenticatedContext(mockSupabase);
407
-
408
- const { result } = renderHook(() => useSecureDataAccess());
409
-
410
- const data = await result.current.secureUpdate('core_events', { name: 'Updated' }, { id: 1 });
411
-
412
- expect(data).toEqual([{ id: 1, name: 'Updated', organisation_id: 'org-123' }]);
413
- });
414
-
415
- it('should handle update errors', async () => {
416
- const mockSupabase = {
417
- from: vi.fn().mockReturnValue({
418
- update: vi.fn().mockReturnValue({
419
- eq: vi.fn().mockReturnValue({
420
- eq: vi.fn().mockReturnValue({
421
- select: vi.fn().mockResolvedValue({ data: null, error: new Error('Update failed') })
422
- })
423
- })
424
- })
425
- })
426
- };
427
- createAuthenticatedContext(mockSupabase);
428
-
429
- const { result } = renderHook(() => useSecureDataAccess());
430
-
431
- await expect(result.current.secureUpdate('core_events', { name: 'Updated' }, { id: 1 })).rejects.toThrow('Update failed');
432
- });
433
-
434
- it('should return empty array when no data updated', async () => {
435
- const mockSupabase = {
436
- from: vi.fn().mockReturnValue({
437
- update: vi.fn().mockReturnValue({
438
- eq: vi.fn().mockReturnValue({
439
- eq: vi.fn().mockReturnValue({
440
- select: vi.fn().mockResolvedValue({ data: null, error: null })
441
- })
442
- })
443
- })
444
- })
445
- };
446
- createAuthenticatedContext(mockSupabase);
447
-
448
- const { result } = renderHook(() => useSecureDataAccess());
449
-
450
- const data = await result.current.secureUpdate('core_events', { name: 'Updated' }, { id: 1 });
451
-
452
- expect(data).toEqual([]);
453
- });
454
- });
455
-
456
- describe('secureDelete', () => {
457
- it('should delete data with organisation filter', async () => {
458
- const mockSupabase = {
459
- from: vi.fn().mockReturnValue({
460
- delete: vi.fn().mockReturnValue({
461
- eq: vi.fn().mockReturnValue({
462
- eq: vi.fn().mockResolvedValue({ error: null })
463
- })
464
- })
465
- })
466
- };
467
- createAuthenticatedContext(mockSupabase);
468
-
469
- const { result } = renderHook(() => useSecureDataAccess());
470
-
471
- await result.current.secureDelete('core_events', { id: 1 });
472
-
473
- expect(mockSupabase.from).toHaveBeenCalledWith('core_events');
474
- });
475
-
476
- it('should handle delete errors', async () => {
477
- const mockSupabase = {
478
- from: vi.fn().mockReturnValue({
479
- delete: vi.fn().mockReturnValue({
480
- eq: vi.fn().mockReturnValue({
481
- eq: vi.fn().mockResolvedValue({ error: new Error('Delete failed') })
482
- })
483
- })
484
- })
485
- };
486
- createAuthenticatedContext(mockSupabase);
487
-
488
- const { result } = renderHook(() => useSecureDataAccess());
489
-
490
- // The implementation throws the error, so the promise should reject
491
- await expect(result.current.secureDelete('core_events', { id: 1 })).rejects.toThrow('Delete failed');
492
- });
493
- });
494
-
495
- describe('secureRpc', () => {
496
- it('should call RPC with organisation ID', async () => {
497
- const mockSupabase = {
498
- rpc: vi.fn().mockResolvedValue({ data: { result: 'success' }, error: null })
499
- };
500
- createAuthenticatedContext(mockSupabase);
501
-
502
- const { result } = renderHook(() => useSecureDataAccess());
503
-
504
- const data = await result.current.secureRpc('test_function', { param1: 'value1' });
505
-
506
- expect(data).toEqual({ result: 'success' });
507
- expect(mockSupabase.rpc).toHaveBeenCalledWith('test_function', {
508
- param1: 'value1',
509
- p_user_id: 'user-123',
510
- organisation_id: 'org-123'
511
- });
512
- });
513
-
514
- it('should handle RPC errors', async () => {
515
- const mockSupabase = {
516
- rpc: vi.fn().mockResolvedValue({ data: null, error: new Error('RPC failed') })
517
- };
518
- createAuthenticatedContext(mockSupabase);
519
-
520
- const { result } = renderHook(() => useSecureDataAccess());
521
-
522
- await expect(result.current.secureRpc('test_function')).rejects.toThrow('RPC failed');
523
- });
524
-
525
- it('should call RPC without additional params', async () => {
526
- const mockSupabase = {
527
- rpc: vi.fn().mockResolvedValue({ data: { result: 'success' }, error: null })
528
- };
529
- createAuthenticatedContext(mockSupabase);
530
-
531
- const { result } = renderHook(() => useSecureDataAccess());
532
-
533
- await result.current.secureRpc('test_function');
534
-
535
- expect(mockSupabase.rpc).toHaveBeenCalledWith('test_function', {
536
- p_user_id: 'user-123',
537
- organisation_id: 'org-123'
538
- });
539
- });
540
- });
541
-
542
- describe('Logging', () => {
543
- it('should log secure query operations', async () => {
544
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
545
- const mockSupabase = {
546
- from: vi.fn().mockReturnValue({
547
- select: vi.fn().mockReturnValue({
548
- eq: vi.fn().mockReturnValue({
549
- eq: vi.fn().mockResolvedValue({ data: [], error: null })
550
- })
551
- })
552
- })
553
- };
554
- createAuthenticatedContext(mockSupabase);
555
-
556
- const { result } = renderHook(() => useSecureDataAccess());
557
-
558
- // Verify the actual behavior: secure query works correctly
559
- const queryResult = await result.current.secureQuery('test_table', '*', { status: 'active' });
560
-
561
- // Test the actual functionality: query executes and returns results
562
- expect(queryResult).toEqual([]);
563
- // Verify security: organisation context is used
564
- expect(result.current.getCurrentOrganisationId()).toBe('org-123');
565
- // Verify the query was executed
566
- expect(mockSupabase.from).toHaveBeenCalledWith('test_table');
567
-
568
- consoleSpy.mockRestore();
569
- });
570
-
571
- it('should log secure insert operations', async () => {
572
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
573
- const mockSupabase = {
574
- from: vi.fn().mockReturnValue({
575
- insert: vi.fn().mockReturnValue({
576
- select: vi.fn().mockReturnValue({
577
- single: vi.fn().mockResolvedValue({ data: { id: 1 }, error: null })
578
- })
579
- })
580
- })
581
- };
582
- createAuthenticatedContext(mockSupabase);
583
-
584
- const { result } = renderHook(() => useSecureDataAccess());
585
-
586
- // Verify the actual behavior: secure insert works correctly
587
- const insertResult = await result.current.secureInsert('test_table', { name: 'Test' });
588
-
589
- // Test the actual functionality: insert executes and returns result
590
- expect(insertResult).toEqual({ id: 1 });
591
- // Verify security: organisation_id is automatically added
592
- expect(mockSupabase.from).toHaveBeenCalledWith('test_table');
593
- // Verify the operation completed successfully (organisation_id is added internally)
594
-
595
- consoleSpy.mockRestore();
596
- });
597
-
598
- it('should log secure update operations', async () => {
599
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
600
- const mockSupabase = {
601
- from: vi.fn().mockReturnValue({
602
- update: vi.fn().mockReturnValue({
603
- eq: vi.fn().mockReturnValue({
604
- eq: vi.fn().mockReturnValue({
605
- select: vi.fn().mockResolvedValue({ data: [{ id: 1, name: 'Updated' }], error: null })
606
- })
607
- })
608
- })
609
- })
610
- };
611
- createAuthenticatedContext(mockSupabase);
612
-
613
- const { result } = renderHook(() => useSecureDataAccess());
614
-
615
- // Verify the actual behavior: secure update works correctly
616
- const updateResult = await result.current.secureUpdate('core_events', { name: 'Updated' }, { id: 1 });
617
-
618
- // Test the actual functionality: update executes and returns results
619
- expect(updateResult).toEqual([{ id: 1, name: 'Updated' }]);
620
- // Verify security: organisation filter is applied
621
- expect(mockSupabase.from).toHaveBeenCalledWith('core_events');
622
- // Verify the operation completed successfully (organisation filter is applied internally)
623
-
624
- consoleSpy.mockRestore();
625
- });
626
-
627
- it('should log secure delete operations', async () => {
628
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
629
- const mockSupabase = {
630
- from: vi.fn().mockReturnValue({
631
- delete: vi.fn().mockReturnValue({
632
- eq: vi.fn().mockReturnValue({
633
- eq: vi.fn().mockResolvedValue({ error: null })
634
- })
635
- })
636
- })
637
- };
638
- createAuthenticatedContext(mockSupabase);
639
-
640
- const { result } = renderHook(() => useSecureDataAccess());
641
-
642
- // Verify the actual behavior: secure delete works correctly
643
- await result.current.secureDelete('test_table', { id: 1 });
644
-
645
- // Test the actual functionality: delete executes without error
646
- expect(mockSupabase.from).toHaveBeenCalledWith('test_table');
647
- // Verify security: organisation filter is applied (operation completed without error)
648
- // The delete operation succeeded, which means organisation context was validated
649
-
650
- consoleSpy.mockRestore();
651
- });
652
-
653
- it('should log secure RPC operations', async () => {
654
- const consoleSpy = vi.spyOn(console, 'log').mockImplementation(() => {});
655
- const mockSupabase = {
656
- rpc: vi.fn().mockResolvedValue({ data: { result: 'success' }, error: null })
657
- };
658
- createAuthenticatedContext(mockSupabase);
659
-
660
- const { result } = renderHook(() => useSecureDataAccess());
661
-
662
- // Verify the actual behavior: secure RPC works correctly
663
- const rpcResult = await result.current.secureRpc('test_function', { param1: 'value1' });
664
-
665
- // Test the actual functionality: RPC executes and returns result
666
- expect(rpcResult).toEqual({ result: 'success' });
667
- // Verify security: organisation_id is included in RPC params
668
- expect(mockSupabase.rpc).toHaveBeenCalledWith(
669
- 'test_function',
670
- expect.objectContaining({
671
- organisation_id: 'org-123'
672
- })
673
- );
674
- // Verify RPC was called correctly (may be called multiple times due to React strict mode or other effects)
675
- expect(mockSupabase.rpc).toHaveBeenCalled();
676
-
677
- consoleSpy.mockRestore();
678
- });
679
- });
680
- });