@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/rbac/utils/clientSecurity.ts","../src/rbac/secureClient.ts","../src/rbac/hooks/useResolvedScope.ts","../src/rbac/hooks/useRBAC.ts","../src/rbac/hooks/permissions/useAccessLevel.ts","../src/rbac/hooks/permissions/useCachedPermissions.ts","../src/rbac/hooks/permissions/useCan.ts","../src/rbac/utils/deep-equal.ts","../src/rbac/hooks/permissions/useHasAllPermissions.ts","../src/rbac/hooks/permissions/useHasAnyPermission.ts","../src/rbac/hooks/permissions/useMultiplePermissions.ts","../src/rbac/hooks/permissions/usePermissions.ts","../src/rbac/hooks/useResourcePermissions.ts","../src/rbac/hooks/useRoleManagement.ts","../src/rbac/hooks/useSecureSupabase.ts"],"sourcesContent":["/**\n * Client Security Detection Utilities\n * @package @jmruthers/pace-core\n * @module RBAC/Utils/ClientSecurity\n * @since 1.0.0\n * \n * Utilities to detect and warn about insecure Supabase client usage.\n */\n\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\n\n/**\n * Symbol to mark secure clients\n * This is attached to clients created by SecureSupabaseClient\n */\nexport const SECURE_CLIENT_SYMBOL = Symbol('pace-core-secure-client');\n\n/**\n * Check if a Supabase client is a secure client (created via useSecureSupabase or createSecureClient)\n * \n * @param client - The Supabase client to check\n * @returns true if the client is secure, false otherwise\n * \n * @example\n * ```tsx\n * import { isSecureClient } from '@jmruthers/pace-core/rbac/utils/clientSecurity';\n * \n * const supabase = useSecureSupabase();\n * if (isSecureClient(supabase)) {\n * // Client is secure, safe to use\n * }\n * ```\n */\nexport function isSecureClient(client: SupabaseClient<Database> | null | undefined): boolean {\n if (!client) return false;\n \n // Check for the secure client symbol\n return (client as any)[SECURE_CLIENT_SYMBOL] === true;\n}\n\n/**\n * Warn about insecure client usage in development\n * \n * @param client - The client being used\n * @param context - Context about where the client is being used (for better error messages)\n * \n * @example\n * ```tsx\n * import { warnIfInsecureClient } from '@jmruthers/pace-core/rbac/utils/clientSecurity';\n * \n * const supabase = createClient(...); // Wrong!\n * warnIfInsecureClient(supabase, 'MyComponent');\n * ```\n */\nexport function warnIfInsecureClient(\n client: SupabaseClient<Database> | null | undefined,\n context?: string\n): void {\n // Only warn in development\n if (typeof process !== 'undefined' && process.env.NODE_ENV === 'production') {\n return;\n }\n \n if (!client) return;\n \n if (!isSecureClient(client)) {\n const contextMsg = context ? ` in ${context}` : '';\n console.warn(\n `[pace-core Security Warning] Non-secure Supabase client detected${contextMsg}.\\n` +\n `You are using a Supabase client created with createClient() instead of useSecureSupabase().\\n` +\n `This bypasses organisation context enforcement and RLS policies, which can lead to:\\n` +\n `- Cross-organisation data access\\n` +\n `- Security vulnerabilities\\n` +\n `- Data leakage between organisations\\n\\n` +\n `Fix: Replace with:\\n` +\n ` import { useSecureSupabase } from '@jmruthers/pace-core/rbac';\\n` +\n ` const supabase = useSecureSupabase();\\n\\n` +\n `See: https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/rbac/getting-started.md`\n );\n }\n}\n\n/**\n * Mark a client as secure (internal use only)\n * This is called by SecureSupabaseClient to mark clients as secure\n * \n * @internal\n */\nexport function markClientAsSecure(client: SupabaseClient<Database>): void {\n (client as any)[SECURE_CLIENT_SYMBOL] = true;\n}\n\n","/**\n * Secure Supabase Client for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/SecureClient\n * @since 1.0.0\n * \n * This module provides a secure Supabase client that enforces organisation context\n * and prevents direct database access outside of the RBAC system.\n */\n\nimport { createClient, SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../types/database';\nimport { UUID } from './types';\nimport { OrganisationContextRequiredError } from './types';\nimport { markClientAsSecure } from './utils/clientSecurity';\n\n/**\n * Secure Supabase Client that enforces organisation context\n * \n * This client automatically injects organisation context into all requests\n * and prevents queries that don't have the required context.\n * \n * Note: For non-super-admins, organisationId is required. Super-admins can operate\n * without organisationId to access system-wide tables (like core_organisations).\n * Callers should derive organisationId from eventId before creating this client\n * if working with event-required apps.\n */\nexport class SecureSupabaseClient {\n private supabase: SupabaseClient<Database>;\n private edgeFunctionClient: SupabaseClient<Database> | null = null;\n private supabaseUrl: string;\n private supabaseKey: string;\n private organisationId: UUID | null;\n private eventId?: string;\n private appId?: UUID;\n private isSuperAdmin: boolean;\n private usesExistingClient: boolean = false;\n \n // Cache for RPC function signatures to avoid repeated database queries\n // Maps function name -> Set of parameter names it accepts\n private static rpcSignatureCache = new Map<string, Set<string>>();\n\n /**\n * RPC functions that are safe to call without organisation context.\n *\n * These functions must:\n * - rely on JWT context (auth.uid()) for authentication\n * - not read or write organisation-scoped data\n *\n * This allowlist enables compliant consuming apps to use `secureSupabase.rpc(...)`\n * even before an organisation is selected (common during initial page load/refresh).\n */\n private static readonly GLOBAL_RPC_ALLOWLIST = new Set<string>([\n 'data_rbac_apps_list',\n ]);\n\n constructor(\n supabaseUrl: string,\n supabaseKey: string,\n organisationId: UUID | null,\n eventId?: string,\n appId?: UUID,\n isSuperAdmin: boolean = false,\n existingClient?: SupabaseClient<Database>\n ) {\n this.supabaseUrl = supabaseUrl;\n this.supabaseKey = supabaseKey;\n this.organisationId = organisationId;\n this.eventId = eventId;\n this.appId = appId;\n this.isSuperAdmin = isSuperAdmin;\n\n // Prefer reusing an existing authenticated client (avoids multiple GoTrue instances\n // and ensures auth context is present for RLS policies).\n if (existingClient) {\n this.supabase = existingClient;\n this.usesExistingClient = true;\n } else {\n // Create the base Supabase client with context headers\n // Note: We'll override functions.invoke to exclude headers for Edge Functions\n // as they may not have CORS configured to accept custom headers\n this.supabase = createClient<Database>(supabaseUrl, supabaseKey, {\n global: {\n headers: {\n 'x-organisation-id': organisationId || '',\n 'x-event-id': eventId || '',\n 'x-app-id': appId || '',\n },\n },\n });\n }\n\n // Override the auth methods to inject context\n this.setupContextInjection();\n \n // Override functions.invoke to exclude custom headers for Edge Functions\n // Edge Functions may not have CORS configured to accept custom headers\n this.setupEdgeFunctionHandling();\n \n // Mark the client as secure\n markClientAsSecure(this.supabase);\n }\n\n /**\n * Setup context injection for all database operations\n */\n private setupContextInjection() {\n const originalFrom = this.supabase.from.bind(this.supabase);\n \n (this.supabase as any).from = (table: string): any => {\n // Validate context before allowing database operations.\n // Some tables are not organisation-scoped (e.g. rbac_apps) and must be queryable\n // without organisation context for initial bootstrapping.\n this.validateContextForTable(table);\n \n // Type assertion needed because table is a string but Supabase expects specific table names\n const query = originalFrom(table as any);\n \n // Store table name on query object so we can access it in filter methods\n (query as any)._tableName = table;\n \n // Inject organisation context into all queries\n return this.injectContext(query, table);\n };\n\n const originalRpc = this.supabase.rpc.bind(this.supabase);\n \n // Override rpc method to inject context\n // Type assertion needed because we're wrapping the generic rpc method\n // The fn parameter is typed as string to match Supabase's rpc signature\n (this.supabase as any).rpc = (fn: string, args?: any, options?: any): any => {\n // Validate context before allowing RPC calls.\n // Some RPCs are global (not organisation-scoped) but still require auth.uid() from JWT.\n // Allow these even without organisation context.\n this.validateContextForRpc(fn);\n\n // SYSTEMIC FIX: Use opt-in whitelist approach instead of brittle blacklist.\n // PostgREST matches RPCs by *exact* parameter signature; sending unexpected params results in:\n // - HTTP 404 + PGRST202 \"Could not find the function ... with parameters ...\"\n //\n // By default, we don't inject context unless the function is explicitly whitelisted.\n // This prevents PGRST202 errors and makes the system more maintainable.\n const acceptedParams = this.getRpcAcceptedParams(fn);\n \n // Only inject context parameters that:\n // 1. The function accepts (according to our whitelist)\n // 2. Are not already explicitly provided\n // 3. We have values for\n // IMPORTANT: Do NOT overwrite explicitly provided RPC parameters.\n // Some RPCs legitimately take `p_app_id`/`p_event_id` as the *target* entity,\n // which may differ from the current RBAC scope app/event.\n const safeArgs = (args ?? {}) as Record<string, unknown>;\n const contextArgs: Record<string, unknown> = { ...safeArgs };\n \n if (acceptedParams.has('p_organisation_id') && \n this.organisationId && \n safeArgs.p_organisation_id === undefined) {\n contextArgs.p_organisation_id = this.organisationId;\n }\n \n if (acceptedParams.has('p_event_id') && \n this.eventId && \n safeArgs.p_event_id === undefined) {\n contextArgs.p_event_id = this.eventId;\n }\n \n if (acceptedParams.has('p_app_id') && \n this.appId && \n safeArgs.p_app_id === undefined) {\n contextArgs.p_app_id = this.appId;\n }\n \n return originalRpc(fn as any, contextArgs, options);\n };\n }\n\n /**\n * Setup Edge Function handling to bypass custom headers\n * Edge Functions may not have CORS configured to accept custom headers,\n * so we create a separate client without custom headers for Edge Function calls\n * \n * NOTE: We store the edge function client but don't override functions here.\n * Instead, we provide a method to get the edge function client for direct use.\n * This avoids interfering with the main client's operations.\n */\n private setupEdgeFunctionHandling() {\n // IMPORTANT:\n // Do not create a second Supabase client when we are already reusing an authenticated\n // base client (this triggers \"Multiple GoTrueClient instances\" warnings and can cause\n // session/auth desync that breaks RLS-protected reads).\n //\n // If we're using an existing client, just use it for Edge Functions too.\n if (this.usesExistingClient) {\n this.edgeFunctionClient = null;\n return;\n }\n\n // Otherwise, create a separate client without the custom RBAC headers for Edge Functions.\n // This prevents CORS errors when Edge Functions don't accept custom headers.\n this.edgeFunctionClient = createClient<Database>(this.supabaseUrl, this.supabaseKey);\n }\n\n /**\n * Get a client for Edge Function calls without custom headers\n * Edge Functions may not have CORS configured to accept custom headers\n * @returns Supabase client without custom headers for Edge Function calls\n */\n getEdgeFunctionClient(): SupabaseClient<Database> {\n return this.edgeFunctionClient || this.supabase;\n }\n\n /**\n * Inject organisation context into a query\n */\n private injectContext(query: any, tableName: string) {\n const originalSelect = query.select.bind(query);\n const originalInsert = query.insert.bind(query);\n const originalUpdate = query.update.bind(query);\n const originalDelete = query.delete.bind(query);\n\n // Override select to add organisation filter\n query.select = (columns?: string) => {\n const result = originalSelect(columns);\n // Store table name on query object so we can access it in filter methods\n (result as any)._tableName = tableName;\n return this.addOrganisationFilter(result, tableName);\n };\n\n // Override insert to add organisation context\n query.insert = (values: any) => {\n // Tables that don't have organisation_id column\n const tablesWithoutOrganisationId = [\n 'core_organisations', // Organisation table itself - uses 'id' as primary key\n 'rbac_apps', // App configuration table - no organisation scope\n 'rbac_app_pages', // Page configuration table - scoped by app_id, not organisation_id\n 'rbac_global_roles', // Global roles - no organisation scope\n ];\n \n // Skip adding organisation_id for tables that don't have it\n if (tablesWithoutOrganisationId.includes(tableName)) {\n return originalInsert(values);\n }\n \n // For rbac_user_profiles, only add organisation_id if not super admin\n // Super admins can create users in any org, non-super-admins are restricted\n if (tableName === 'rbac_user_profiles') {\n if (this.isSuperAdmin) {\n // Super admin: Don't force organisation_id (can be set explicitly if needed)\n return originalInsert(values);\n }\n // Non-super-admin: Add organisation_id as defense in depth\n // organisationId should always be available for non-super-admins (validateContext ensures this)\n if (!this.organisationId) {\n throw new OrganisationContextRequiredError();\n }\n const contextValues = Array.isArray(values) \n ? values.map(v => ({ ...v, organisation_id: this.organisationId }))\n : { ...values, organisation_id: this.organisationId };\n return originalInsert(contextValues);\n }\n \n // For other tables, add organisation_id if available\n // Super-admins might not have organisationId set, so allow them to set it explicitly\n if (this.isSuperAdmin && !this.organisationId) {\n // Super admin without organisationId: Don't force it (can be set explicitly if needed)\n return originalInsert(values);\n }\n \n // Non-super-admin or super-admin with organisationId: Add organisation_id\n // organisationId should always be available for non-super-admins (validateContext ensures this)\n if (!this.organisationId) {\n throw new OrganisationContextRequiredError();\n }\n const contextValues = Array.isArray(values) \n ? values.map(v => ({ ...v, organisation_id: this.organisationId }))\n : { ...values, organisation_id: this.organisationId };\n \n return originalInsert(contextValues);\n };\n\n // Override update to add organisation filter\n query.update = (values: any) => {\n const result = originalUpdate(values);\n return this.addOrganisationFilter(result, tableName);\n };\n\n // Override delete to add organisation filter\n query.delete = () => {\n const result = originalDelete();\n return this.addOrganisationFilter(result, tableName);\n };\n\n return query;\n }\n\n /**\n * Add organisation filter to a query\n * \n * Defense in depth strategy:\n * - RLS policies are the primary security layer (cannot be bypassed)\n * - Application-level filtering adds an additional layer of protection\n * \n * For rbac_user_profiles:\n * - Super admins: No org filter (see all users) - RLS will allow access\n * - Non-super-admins: Apply org filter as defense in depth - RLS will also filter\n * \n * For system-wide tables (like core_organisations):\n * - Super admins: No org filter (see all records) - RLS will allow access\n * - Non-super-admins: Apply org filter as defense in depth - RLS will also filter\n * \n * For other tables:\n * - Always apply org filter unless super admin bypasses it\n */\n private addOrganisationFilter(query: any, tableName: string) {\n // Tables that don't have organisation_id column - RLS policies handle access control\n const tablesWithoutOrganisationId = [\n 'core_organisations', // Organisation table itself - uses 'id' as primary key\n 'rbac_apps', // App configuration table - no organisation scope\n 'rbac_app_pages', // Page configuration table - scoped by app_id, not organisation_id\n 'rbac_global_roles', // Global roles - no organisation scope\n // Person-scoped tables (organisation_id was removed in person-scoped profiles migration)\n 'core_person', // Person records - person-scoped, no organisation_id\n 'core_member', // Member profiles - person-scoped, no organisation_id\n 'core_contact', // Contact profiles - person-scoped, no organisation_id\n 'core_consent', // Consent records - person-scoped, no organisation_id\n 'core_identification', // Identification records - person-scoped, no organisation_id\n 'core_qualification', // Qualification records - person-scoped, no organisation_id\n 'medi_profile', // Medical profiles - person-scoped, no organisation_id\n 'medi_condition', // Medical conditions - person-scoped via medi_profile, no organisation_id\n 'medi_diet', // Medical diets - person-scoped via medi_profile, no organisation_id\n 'medi_action_plan', // Medical action plans - person-scoped via medi_profile, no organisation_id\n 'medi_profile_versions', // Medical profile versions - person-scoped via medi_profile, no organisation_id\n ];\n \n // Skip organisation filter for tables that don't have organisation_id column\n if (tablesWithoutOrganisationId.includes(tableName)) {\n return query; // RLS policies handle access control for these tables\n }\n\n // If organisation context is not set, don't add a filter (e.g., super admin without selected org)\n if (!this.organisationId) {\n return query;\n }\n \n // System-wide tables that super-admins should be able to query without organisation filters\n // These tables have organisation_id but super-admins need to see all records\n const systemWideTablesForSuperAdmins = [\n 'core_organisations', // Super-admins need to see all organisations\n ];\n \n // For system-wide tables, super-admins bypass organisation filter\n if (systemWideTablesForSuperAdmins.includes(tableName) && this.isSuperAdmin) {\n return query; // No filter - RLS handles access control\n }\n \n // For rbac_user_profiles, use conditional filtering based on super admin status\n if (tableName === 'rbac_user_profiles') {\n // Super admins: No org filter (see all users via RLS)\n if (this.isSuperAdmin) {\n return query; // No filter - RLS handles access control\n }\n \n // For non-super-admins: Apply org filter, but allow NULL organisation_id\n // User profiles can have organisation_id = NULL (users not yet assigned to an org)\n // We use .or() to allow either matching organisation_id OR NULL\n // RLS policies will still enforce access control\n return query.or(`organisation_id.eq.${this.organisationId},organisation_id.is.null`);\n }\n \n // For all other tables, apply organisation filter\n // Super admins can still bypass via RLS if needed, but we filter at app level too\n if (this.isSuperAdmin) {\n // Super admins might want to see cross-org data, but for most tables\n // we still apply the filter as a safety measure (they can override if needed)\n // For now, we'll apply it - super admins can use direct queries if they need cross-org access\n return query.eq('organisation_id', this.organisationId);\n }\n \n // Non-super-admins: Always apply org filter\n return query.eq('organisation_id', this.organisationId);\n }\n\n /**\n * Validate that required context is present\n * Super-admins can operate without organisation context\n */\n private validateContext() {\n // Super-admins can operate without organisation context\n if (this.isSuperAdmin) {\n return;\n }\n \n if (!this.organisationId) {\n throw new OrganisationContextRequiredError();\n }\n }\n\n /**\n * Determine whether a table requires organisation context.\n * Tables without an organisation_id column (or global configuration tables) are safe without org context.\n */\n private tableRequiresOrganisationContext(tableName: string): boolean {\n // Keep this list aligned with the tables handled in `addOrganisationFilter` / `injectContext`.\n const tablesWithoutOrganisationId = new Set<string>([\n 'core_organisations',\n 'rbac_apps',\n 'rbac_app_pages',\n 'rbac_global_roles',\n 'core_person',\n 'core_member',\n 'core_contact',\n 'core_consent',\n 'core_identification',\n 'core_qualification',\n 'medi_profile',\n 'medi_condition',\n 'medi_diet',\n 'medi_action_plan',\n 'medi_profile_versions',\n ]);\n\n return !tablesWithoutOrganisationId.has(tableName);\n }\n\n /**\n * Validate context for a specific table operation.\n */\n private validateContextForTable(tableName: string) {\n if (this.isSuperAdmin) return;\n if (!this.organisationId && this.tableRequiresOrganisationContext(tableName)) {\n throw new OrganisationContextRequiredError();\n }\n }\n\n /**\n * Validate context for a specific RPC call.\n */\n private validateContextForRpc(fn: string) {\n if (this.isSuperAdmin) return;\n if (SecureSupabaseClient.GLOBAL_RPC_ALLOWLIST.has(fn)) return;\n this.validateContext();\n }\n\n /**\n * Get the current organisation ID\n */\n getOrganisationId(): UUID | null {\n return this.organisationId;\n }\n\n /**\n * Get the current event ID\n */\n getEventId(): string | undefined {\n return this.eventId;\n }\n\n /**\n * Get the current app ID\n */\n getAppId(): UUID | undefined {\n return this.appId;\n }\n\n /**\n * Create a new client with updated context\n */\n withContext(updates: {\n organisationId?: UUID | null;\n eventId?: string;\n appId?: UUID;\n isSuperAdmin?: boolean;\n }): SecureSupabaseClient {\n return new SecureSupabaseClient(\n this.supabaseUrl,\n this.supabaseKey,\n updates.organisationId !== undefined ? updates.organisationId : this.organisationId,\n updates.eventId !== undefined ? updates.eventId : this.eventId,\n updates.appId !== undefined ? updates.appId : this.appId,\n updates.isSuperAdmin !== undefined ? updates.isSuperAdmin : this.isSuperAdmin\n );\n }\n\n /**\n * Get the underlying Supabase client (for internal use only)\n * @internal\n */\n getClient(): SupabaseClient<Database> {\n // Return a proxy that intercepts functions.invoke calls to use edge function client\n // This avoids CORS issues with Edge Functions while keeping the main client intact\n const proxiedClient = new Proxy(this.supabase, {\n get: (target, prop) => {\n if (prop === 'functions' && this.edgeFunctionClient) {\n // Return the edge function client's functions for invoke calls\n // This bypasses custom headers that cause CORS errors\n return this.edgeFunctionClient.functions;\n }\n // For all other properties, return the original\n return (target as any)[prop];\n }\n }) as SupabaseClient<Database>;\n \n // Mark the proxied client as secure\n markClientAsSecure(proxiedClient);\n \n return proxiedClient;\n }\n\n /**\n * Get the set of parameter names that an RPC function accepts.\n * Uses a static whitelist of RPCs that we know accept context parameters.\n * \n * This is an opt-in approach: by default, we don't inject context unless\n * the function is explicitly whitelisted. This prevents PGRST202 errors from\n * injecting unexpected parameters.\n * \n * @param fn - The RPC function name\n * @returns Set of parameter names the function accepts\n */\n private getRpcAcceptedParams(fn: string): Set<string> {\n // Check cache first\n if (SecureSupabaseClient.rpcSignatureCache.has(fn)) {\n return SecureSupabaseClient.rpcSignatureCache.get(fn)!;\n }\n\n // Whitelist of RPCs that accept context parameters\n // Format: function name -> Set of parameters it accepts\n // \n // SYSTEMIC FIX: This is an opt-in approach. By default, we don't inject context\n // unless the function is explicitly whitelisted. This prevents PGRST202 errors\n // from injecting unexpected parameters.\n //\n // To add a new RPC:\n // 1. Check the function signature in the database: \n // SELECT pg_get_function_identity_arguments(oid) FROM pg_proc WHERE proname = 'function_name';\n // 2. Add it here with the parameters it accepts\n const rpcContextWhitelist: Record<string, Set<string>> = {\n // RPCs that accept all three context parameters\n 'rbac_roles_list': new Set(['p_organisation_id', 'p_event_id', 'p_app_id']),\n \n // RPCs that accept only p_organisation_id (not p_app_id or p_event_id)\n 'data_file_reference_by_category_list': new Set(['p_organisation_id']),\n \n // Add more RPCs here as we discover them\n // Format: 'function_name': new Set(['p_organisation_id', 'p_event_id', 'p_app_id']),\n };\n\n // Default: empty set (no context injection) unless whitelisted\n // This is the safe default - prevents PGRST202 errors\n const acceptedParams = rpcContextWhitelist[fn] || new Set<string>();\n \n // Cache the result to avoid repeated lookups\n SecureSupabaseClient.rpcSignatureCache.set(fn, acceptedParams);\n \n return acceptedParams;\n }\n}\n\n /**\n * Create a secure Supabase client with organisation context\n * \n * @param supabaseUrl - Supabase project URL\n * @param supabaseKey - Supabase publishable key or anon key (accepts both legacy anon keys and modern publishable keys)\n * @param organisationId - Organisation ID (optional for super-admins)\n * @param eventId - Optional event ID\n * @param appId - Optional app ID\n * @param isSuperAdmin - Optional super admin flag (defaults to false). When true, organisationId can be null.\n * @returns SecureSupabaseClient instance\n * \n * @example\n * ```typescript\n * const client = createSecureClient(\n * 'https://your-project.supabase.co',\n * 'your-publishable-key-or-anon-key',\n * 'org-123',\n * 'event-456',\n * 'app-789',\n * false // isSuperAdmin\n * );\n * \n * // For super-admins, organisationId can be null\n * const superAdminClient = createSecureClient(\n * 'https://your-project.supabase.co',\n * 'your-publishable-key-or-anon-key',\n * null, // organisationId not required for super-admins\n * undefined,\n * undefined,\n * true // isSuperAdmin\n * );\n * ```\n */\nexport function createSecureClient(\n supabaseUrl: string,\n supabaseKey: string,\n organisationId: UUID | null,\n eventId?: string,\n appId?: UUID,\n isSuperAdmin: boolean = false\n): SecureSupabaseClient {\n return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin);\n}\n\n/**\n * Create a secure client from an existing Supabase client\n * \n * @param client - Existing Supabase client\n * @param organisationId - Required organisation ID\n * @param eventId - Optional event ID\n * @param appId - Optional app ID\n * @returns SecureSupabaseClient instance\n */\nexport function fromSupabaseClient(\n client: SupabaseClient<Database>,\n organisationId: UUID | null,\n eventId?: string,\n appId?: UUID,\n isSuperAdmin: boolean = false\n): SecureSupabaseClient {\n // Wrap the existing client to reuse auth/session while enforcing organisation/event/app context.\n // URL/key are unused in this mode.\n return new SecureSupabaseClient('', '', organisationId, eventId, appId, isSuperAdmin, client);\n}\n","/**\n * @file useResolvedScope Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * Shared hook for resolving RBAC scope from various contexts.\n * This hook is used by both DataTable and PagePermissionGuard to ensure\n * consistent scope resolution logic.\n */\n\nimport { useEffect, useState, useRef, useMemo } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../../types/database';\nimport type { Scope } from '../types';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { createLogger } from '../../utils/core/logger';\n\nconst log = createLogger('useResolvedScope');\n\n// Cache app config to avoid repeated database queries\n// App config rarely changes during a session, so we can cache it\nconst appIdCache = new Map<string, { appId: string; timestamp: number }>();\nconst CACHE_TTL = 5 * 60 * 1000; // 5 minutes\n\n// Export function to clear cache (for testing)\nexport function clearAppConfigCache(): void {\n appIdCache.clear();\n}\n\nexport interface UseResolvedScopeOptions {\n /** Supabase client instance */\n supabase: SupabaseClient<Database> | null;\n /** Selected organisation ID */\n selectedOrganisationId: string | null;\n /** Selected event ID */\n selectedEventId: string | null;\n}\n\nexport interface UseResolvedScopeReturn {\n /** Resolved scope, or null if not yet resolved */\n resolvedScope: Scope | null;\n /** Whether the scope resolution is in progress */\n isLoading: boolean;\n /** Error if scope resolution failed */\n error: Error | null;\n}\n\n/**\n * Resolves RBAC scope from organisation and event context\n * \n * This hook handles the complex logic of determining the correct RBAC scope\n * based on available context (organisation, event, app). It ensures consistent\n * scope resolution across the application.\n * \n * @param options - Hook options\n * @returns Resolved scope and loading state\n * \n * @example\n * ```tsx\n * const { resolvedScope, isLoading } = useResolvedScope({\n * supabase,\n * selectedOrganisationId,\n * selectedEventId\n * });\n * \n * if (isLoading) return <Loading />;\n * if (!resolvedScope) return <Error />;\n * \n * const permission = useCan(userId, resolvedScope, permission);\n * ```\n */\nexport function useResolvedScope({\n supabase,\n selectedOrganisationId,\n selectedEventId\n}: UseResolvedScopeOptions): UseResolvedScopeReturn {\n const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n \n // Use a ref to track the stable scope and only update it when it actually changes\n const stableScopeRef = useRef<{ organisationId: string; appId: string; eventId: string | undefined }>({ \n organisationId: '', \n appId: '', \n eventId: undefined \n });\n \n // Update stable scope ref in useEffect to avoid updates during render\n // For PORTAL, allow scopes without organisationId\n useEffect(() => {\n if (resolvedScope) {\n const newScope = {\n organisationId: resolvedScope.organisationId || '',\n appId: resolvedScope.appId || '',\n eventId: resolvedScope.eventId\n };\n \n // Only update if the scope has actually changed\n if (stableScopeRef.current.organisationId !== newScope.organisationId ||\n stableScopeRef.current.eventId !== newScope.eventId ||\n stableScopeRef.current.appId !== newScope.appId) {\n stableScopeRef.current = {\n organisationId: newScope.organisationId,\n appId: newScope.appId,\n eventId: newScope.eventId\n };\n }\n } else {\n // Reset to empty scope when no resolved scope\n stableScopeRef.current = { organisationId: '', appId: '', eventId: undefined };\n }\n }, [resolvedScope]);\n \n // Get app name to check if it's PORTAL (needed for return logic)\n const appName = getCurrentAppName();\n \n const stableScope = stableScopeRef.current;\n \n useEffect(() => {\n let cancelled = false;\n \n const resolveScope = async () => {\n // OPTIMIZATION: If all inputs are null/undefined, immediately return empty scope\n // This indicates pre-filtered mode where we don't need to resolve scope\n if (!supabase && !selectedOrganisationId && !selectedEventId) {\n if (!cancelled) {\n setResolvedScope(null);\n setIsLoading(false);\n setError(null);\n }\n return;\n }\n \n setIsLoading(true);\n setError(null);\n \n try {\n // Get app name and resolve appId\n const appName = getCurrentAppName();\n let appId: string | undefined = undefined;\n \n // Try to resolve appId from database (with caching)\n // Only query if user is authenticated (RLS policies require authentication)\n if (supabase && appName) {\n try {\n // Check if user is authenticated before querying (RLS requires auth)\n // HTTP 406 errors are expected when not authenticated, so we skip the query\n const { data: session } = await supabase.auth.getSession();\n if (!session?.session) {\n // User not authenticated - skip app resolution, will retry after login\n // This is expected on login pages, so don't log as error\n log.debug(`Skipping app resolution for \"${appName}\" - user not authenticated`);\n } else {\n // Check cache first\n const cached = appIdCache.get(appName);\n const now = Date.now();\n if (cached && (now - cached.timestamp) < CACHE_TTL) {\n appId = cached.appId;\n } else {\n // Cache miss or expired - fetch from database\n const { data: app, error } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .eq('is_active', true)\n .single() as { data: { id: string; name: string; is_active: boolean } | null; error: any };\n \n if (error) {\n // HTTP 406 is expected when not authenticated (RLS blocks query)\n // Don't log as error if it's a 406 - this is expected behavior\n if (error.code === '406' || error.code === 'PGRST116' || error.message?.includes('406')) {\n log.debug(`App resolution blocked by RLS for \"${appName}\" - user may not be authenticated`);\n // Don't cache - will retry after authentication\n appId = undefined;\n } else {\n // Check if app exists but is inactive\n const { data: inactiveApp } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .single() as { data: { id: string; name: string; is_active: boolean } | null };\n \n if (inactiveApp) {\n log.error(`App \"${appName}\" exists but is inactive (is_active: ${inactiveApp.is_active})`);\n // Don't cache inactive apps - set appId to undefined\n appId = undefined;\n } else {\n log.error(`App \"${appName}\" not found in rbac_apps table`, { error });\n // Don't cache missing apps - set appId to undefined\n appId = undefined;\n }\n }\n } else if (app) {\n appId = app.id;\n // Only cache successful lookups of active apps\n appIdCache.set(appName, { appId, timestamp: now });\n }\n }\n }\n } catch (error) {\n // Handle network errors or other unexpected errors gracefully\n // Don't log 406 errors as they're expected when not authenticated\n const errorMessage = error instanceof Error ? error.message : String(error);\n if (!errorMessage.includes('406') && !errorMessage.includes('PGRST116')) {\n log.error('Unexpected error resolving app ID:', error);\n } else {\n log.debug('App resolution skipped - authentication required');\n }\n }\n }\n\n // Build initial scope from available context\n // Scope is now page-level only - use whatever context is available\n // Default to organisation scope if both are available (safest default)\n const initialScope: Scope = {\n organisationId: selectedOrganisationId || undefined,\n eventId: selectedEventId || undefined,\n appId: appId\n };\n\n // For PORTAL/ADMIN apps, allow scope without org/event\n if (appName === 'PORTAL' || appName === 'ADMIN') {\n if (!cancelled) {\n const optionalContextScope: Scope = {\n organisationId: undefined,\n eventId: undefined,\n appId: appId || undefined\n };\n setResolvedScope(optionalContextScope);\n setError(null);\n setIsLoading(false);\n }\n return;\n }\n \n // For other apps, default to organisation scope validation (safest default)\n // Page-level scope will be validated during permission checks\n // ContextValidator is already imported at the top\n const { ContextValidator } = await import('../utils/contextValidator');\n const validation = await ContextValidator.resolveScopeForPage(\n initialScope,\n 'organisation', // Default to organisation scope when no page context\n appName || undefined,\n supabase\n );\n\n if (!validation.isValid) {\n // If validation fails but we have an eventId, return scope with eventId\n // The organisation will be derived later during permission checks\n if (selectedEventId) {\n if (!cancelled) {\n const eventScope: Scope = {\n organisationId: undefined, // Will be derived from event during permission check\n eventId: selectedEventId,\n appId: appId || undefined\n };\n setResolvedScope(eventScope);\n setError(null); // Don't set error - let permission check handle derivation\n setIsLoading(false);\n }\n return;\n }\n \n if (!cancelled) {\n setResolvedScope(null);\n setError(validation.error || new Error('Context validation failed'));\n setIsLoading(false);\n }\n return;\n }\n\n // Set resolved scope\n if (!cancelled) {\n setResolvedScope(validation.resolvedScope);\n setError(null);\n setIsLoading(false);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err as Error);\n setIsLoading(false);\n }\n }\n };\n\n resolveScope();\n \n return () => {\n cancelled = true;\n };\n }, [selectedOrganisationId, selectedEventId, supabase]);\n \n // Return scope if it has appId (for PORTAL/ADMIN) or organisationId (for other apps)\n // For PORTAL/ADMIN, always return a scope (even if empty) so components can use contextAppId\n const allowsOptionalContexts = appName === 'PORTAL' || appName === 'ADMIN';\n const hasValidScope = allowsOptionalContexts\n ? true // PORTAL/ADMIN always have valid scope (even without org/event/appId)\n : (stableScope.appId || stableScope.organisationId);\n \n // CRITICAL FIX: Memoize finalScope to prevent creating new object references on every render\n // This prevents infinite loops in useCan and other hooks that depend on scope equality\n const finalScope: Scope | null = useMemo(() => {\n if (!hasValidScope) {\n return allowsOptionalContexts ? {} : null;\n }\n \n // Build scope object only with defined values to ensure stable reference\n const scope: Scope = {};\n if (stableScope.organisationId) {\n scope.organisationId = stableScope.organisationId;\n }\n if (stableScope.eventId) {\n scope.eventId = stableScope.eventId;\n }\n if (stableScope.appId) {\n scope.appId = stableScope.appId;\n }\n \n return scope;\n }, [hasValidScope, allowsOptionalContexts, stableScope.organisationId, stableScope.eventId, stableScope.appId]);\n \n return {\n resolvedScope: finalScope,\n isLoading,\n error\n };\n}\n","/**\n * @file RBAC Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 0.3.0\n *\n * A React hook that provides access to the RBAC (Role-Based Access Control) system\n * through the hardened RBAC engine API. The hook defers all permission and role\n * resolution to the shared engine to ensure consistent security behaviour across\n * applications.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport {\n getPermissionMap,\n getAccessLevel,\n resolveAppContext,\n getRoleContext,\n getPageScopeType,\n} from '../api';\nimport { getRBACLogger } from '../config';\nimport { ContextValidator } from '../utils/contextValidator';\nimport type {\n UserRBACContext,\n GlobalRole,\n OrganisationRole,\n EventAppRole,\n Permission,\n Scope,\n PermissionMap,\n UUID,\n} from '../types';\n\nfunction mapAccessLevelToEventRole(level: string | null): EventAppRole | null {\n switch (level) {\n case 'viewer':\n return 'viewer';\n case 'participant':\n return 'participant';\n case 'planner':\n return 'planner';\n case 'admin':\n case 'super':\n return 'event_admin';\n default:\n return null;\n }\n}\n\nexport function useRBAC(pageId?: string): UserRBACContext {\n const logger = getRBACLogger();\n // Get all context from UnifiedAuth - it already provides selectedOrganisation, isContextReady, selectedEvent, and eventLoading\n // This is more reliable than calling useOrganisations()/useEvents() separately which might throw or return stale values\n const { \n user, \n session, \n supabase,\n appName, \n appId: contextAppId,\n selectedOrganisation,\n isContextReady: orgContextReady,\n organisationLoading: orgLoading,\n selectedEvent,\n eventLoading\n } = useUnifiedAuth();\n \n // Removed excessive logging - hook initialization logged only on first mount or significant changes\n\n const [globalRole, setGlobalRole] = useState<GlobalRole | null>(null);\n const [organisationRole, setOrganisationRole] = useState<OrganisationRole | null>(null);\n const [eventAppRole, setEventAppRole] = useState<EventAppRole | null>(null);\n const [permissionMap, setPermissionMap] = useState<PermissionMap>({} as PermissionMap);\n const [currentScope, setCurrentScope] = useState<Scope | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const resetState = useCallback(() => {\n setGlobalRole(null);\n setOrganisationRole(null);\n setEventAppRole(null);\n setPermissionMap({} as PermissionMap);\n setCurrentScope(null);\n }, []);\n\n const loadRBACContext = useCallback(async () => {\n // Early return if user is not authenticated - don't do anything\n if (!user || !session) {\n resetState();\n setIsLoading(false);\n return;\n }\n\n // Build initial scope from available context\n // Scope is now page-level only - use whatever context is available\n const initialScope: Scope = {\n organisationId: selectedEvent?.organisation_id || selectedOrganisation?.id || undefined,\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n\n // PORTAL/ADMIN special case: context is always ready\n // For other apps, we need at least one context (org or event) for page-level scope validation\n if (appName !== 'PORTAL' && appName !== 'ADMIN') {\n if (!selectedOrganisation && !selectedEvent) {\n // Wait for context to be available\n setIsLoading(true);\n return;\n }\n }\n\n setIsLoading(true);\n setError(null);\n\n // Loading RBAC context\n\n try {\n let appId: UUID | undefined = contextAppId; // Use contextAppId as default (already resolved in UnifiedAuthProvider)\n \n if (appName && !appId) {\n // Wrap RPC call in try-catch to handle NetworkError gracefully\n try {\n const resolved = await resolveAppContext({ userId: user.id as UUID, appName });\n // For PORTAL/ADMIN apps, allow access even if hasAccess is false (users can view their own profile, super admins have global access)\n if (!resolved) {\n if (appName === 'PORTAL' || appName === 'ADMIN') {\n // For PORTAL/ADMIN, proceed without appId - it's optional for these apps\n // Use contextAppId if available\n } else {\n throw new Error(`User does not have access to app \"${appName}\"`);\n }\n } else if (!resolved.hasAccess && appName !== 'PORTAL' && appName !== 'ADMIN') {\n throw new Error(`User does not have access to app \"${appName}\"`);\n } else {\n appId = resolved.appId;\n }\n } catch (rpcError: any) {\n // Handle NetworkError - might be due to timing issue\n if (rpcError?.message?.includes('NetworkError') || rpcError?.message?.includes('fetch')) {\n logger.warn('[useRBAC] NetworkError resolving app context - may be timing issue, will retry when context is ready', {\n appName,\n error: rpcError.message,\n eventLoading,\n hasSelectedEvent: !!selectedEvent\n });\n // Don't throw - let it retry when dependencies change\n setIsLoading(false);\n return;\n }\n // For PORTAL/ADMIN, allow proceeding without app access check (for profile pages, super admin access)\n if (appName === 'PORTAL' || appName === 'ADMIN') {\n // appId will use contextAppId or be undefined, which is OK for PORTAL/ADMIN page-level permissions\n } else {\n // Re-throw other errors for non-PORTAL apps\n throw rpcError;\n }\n }\n }\n\n // Update scope with appId (use contextAppId as fallback for PORTAL)\n const scope: Scope = {\n ...initialScope,\n appId: appId || contextAppId,\n };\n \n // Resolve scope based on page-level scope type\n // If pageId is provided, use its scope type; otherwise default to 'organisation'\n let pageScopeType: 'event' | 'organisation' | 'both' = 'organisation';\n if (pageId && scope.appId) {\n try {\n pageScopeType = await getPageScopeType(pageId, scope.appId, appName);\n } catch (error) {\n logger.warn('[useRBAC] Failed to get page scope type, defaulting to organisation', {\n pageId,\n error: error instanceof Error ? error.message : String(error)\n });\n // Default to organisation scope on error\n }\n }\n \n // Resolve required context using page-level scope type\n const validation = await ContextValidator.resolveScopeForPage(\n scope,\n pageScopeType,\n appName,\n supabase || null\n );\n\n if (!validation.isValid || !validation.resolvedScope) {\n throw validation.error || new Error('Context validation failed');\n }\n\n const resolvedScope = validation.resolvedScope;\n setCurrentScope(resolvedScope);\n\n // API calls no longer need appConfig (scope is page-level)\n // Pass appName to allow PORTAL/ADMIN apps to work without organisation context\n const [map, roleContext, accessLevel] = await Promise.all([\n getPermissionMap({ userId: user.id as UUID, scope: resolvedScope }, appName),\n getRoleContext({ userId: user.id as UUID, scope: resolvedScope }, appName),\n getAccessLevel({ userId: user.id as UUID, scope: resolvedScope }, appName),\n ]);\n\n setPermissionMap(map);\n setGlobalRole(roleContext.globalRole);\n setOrganisationRole(roleContext.organisationRole);\n setEventAppRole(roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel));\n \n // Only log on first successful load or if there's an issue\n const permissionCount = Object.keys(map).length;\n if (permissionCount === 0) {\n logger.warn('[useRBAC] RBAC context loaded but returned 0 permissions', {\n appName,\n organisationId: resolvedScope.organisationId,\n eventId: resolvedScope.eventId\n });\n }\n } catch (err) {\n const handledError = err instanceof Error ? err : new Error('Failed to load RBAC context');\n logger.error('[useRBAC] Error loading RBAC context:', handledError);\n setError(handledError);\n resetState();\n } finally {\n setIsLoading(false);\n }\n }, [appName, logger, resetState, selectedEvent?.event_id, selectedOrganisation?.id, session, user, eventLoading, orgContextReady, orgLoading]);\n\n const hasGlobalPermission = useCallback(\n (permission: string): boolean => {\n if (globalRole === 'super_admin' || permissionMap['*']) {\n return true;\n }\n\n if (permission === 'super_admin') {\n return globalRole === 'super_admin';\n }\n\n if (permission === 'org_admin') {\n return organisationRole === 'org_admin';\n }\n\n return permissionMap[permission as Permission] === true;\n },\n [globalRole, organisationRole, permissionMap],\n );\n\n const isSuperAdmin = useMemo(() => globalRole === 'super_admin' || permissionMap['*'] === true, [globalRole, permissionMap]);\n const isOrgAdmin = useMemo(() => organisationRole === 'org_admin' || isSuperAdmin, [organisationRole, isSuperAdmin]);\n const isEventAdmin = useMemo(() => eventAppRole === 'event_admin' || isSuperAdmin, [eventAppRole, isSuperAdmin]);\n const canManageOrganisation = useMemo(() => isSuperAdmin || organisationRole === 'org_admin', [isSuperAdmin, organisationRole]);\n const canManageEvent = useMemo(() => isSuperAdmin || eventAppRole === 'event_admin', [isSuperAdmin, eventAppRole]);\n\n useEffect(() => {\n loadRBACContext();\n }, [loadRBACContext, appName, eventLoading, selectedEvent?.event_id, user, session, selectedOrganisation?.id, orgContextReady, orgLoading]);\n\n return {\n user,\n globalRole,\n organisationRole,\n eventAppRole,\n hasGlobalPermission,\n isSuperAdmin,\n isOrgAdmin,\n isEventAdmin,\n canManageOrganisation,\n canManageEvent,\n isLoading,\n error,\n };\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { getAccessLevel } from '../../api';\nimport { OrganisationContextRequiredError } from '../../types';\nimport type { AccessLevel as AccessLevelType, Scope, UUID } from '../../types';\nimport { useAppConfig } from '../../../hooks/useAppConfig';\n\n/**\n * Hook to get user's access level in a scope\n *\n * @param userId - User ID\n * @param scope - Scope for access level checking\n * @returns Access level state and methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { accessLevel, isLoading, error } = useAccessLevel(userId, scope);\n *\n * if (isLoading) return <div>Loading access level...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * Access Level: {accessLevel}\n * {accessLevel >= AccessLevel.ADMIN && <AdminPanel />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useAccessLevel(userId: UUID, scope: Scope): {\n accessLevel: AccessLevelType;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [accessLevel, setAccessLevel] = useState<AccessLevelType>('viewer');\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get appName from context if available (safely handles missing context)\n let appName: string | undefined;\n try {\n const { appName: contextAppName } = useAppConfig();\n appName = contextAppName;\n } catch {\n // Not available, will use undefined\n }\n\n const fetchAccessLevel = useCallback(async () => {\n if (!userId) {\n setAccessLevel('viewer');\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n // Check super admin status first - super admins bypass context requirements\n // This allows super admins to check their access level without organisation context\n const { isSuperAdmin: checkSuperAdmin } = await import('../../api');\n const isSuperAdminUser = await checkSuperAdmin(userId);\n\n if (isSuperAdminUser) {\n setAccessLevel('super');\n setIsLoading(false);\n return;\n }\n\n // Early validation: check if scope has required context\n // PORTAL/ADMIN apps allow both contexts to be optional\n if (appName !== 'PORTAL' && appName !== 'ADMIN' && !scope.organisationId && !scope.eventId) {\n const orgError = new OrganisationContextRequiredError();\n setError(orgError);\n setAccessLevel('viewer');\n setIsLoading(false);\n return;\n }\n\n const level = await getAccessLevel({ userId, scope }, appName);\n setAccessLevel(level);\n } catch (err) {\n const error = err instanceof Error ? err : new Error('Failed to fetch access level');\n setError(error);\n setAccessLevel('viewer');\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, appName]);\n\n useEffect(() => {\n fetchAccessLevel();\n }, [fetchAccessLevel]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n accessLevel,\n isLoading,\n error,\n refetch: fetchAccessLevel\n }), [accessLevel, isLoading, error, fetchAccessLevel]);\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { getPermissionMap } from '../../api';\nimport { PermissionMap, Scope, UUID } from '../../types';\n\n/**\n * Hook to get cached permissions with TTL management\n *\n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @returns Cached permission state and methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { permissions, isLoading, error, invalidateCache } = useCachedPermissions(userId, scope);\n *\n * if (isLoading) return <div>Loading cached permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * {permissions['read:users'] && <UserList />}\n * <button onClick={invalidateCache}>Refresh Permissions</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useCachedPermissions(userId: UUID, scope: Scope): {\n permissions: PermissionMap;\n isLoading: boolean;\n error: Error | null;\n invalidateCache: () => void;\n refetch: () => Promise<void>;\n} {\n const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchCachedPermissions = useCallback(async () => {\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n const permissionMap = await getPermissionMap({ userId, scope });\n setPermissions(permissionMap);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to fetch cached permissions'));\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n const invalidateCache = useCallback(() => {\n // This would typically invalidate the cache in the actual implementation\n // For now, we'll just refetch\n fetchCachedPermissions();\n }, [fetchCachedPermissions]);\n\n useEffect(() => {\n fetchCachedPermissions();\n }, [fetchCachedPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n permissions,\n isLoading,\n error,\n invalidateCache,\n refetch: fetchCachedPermissions\n }), [permissions, isLoading, error, invalidateCache, fetchCachedPermissions]);\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { isPermitted, isPermittedCached } from '../../api';\nimport { getRBACLogger } from '../../config';\nimport { Permission, Scope, UUID } from '../../types';\nimport { scopeEqual } from '../../utils/deep-equal';\n\n/**\n * Hook to check if user can perform an action\n *\n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permission - Permission to check\n * @param pageId - Optional page ID\n * @param useCache - Whether to use cached results\n * @param appName - Optional app name (for PORTAL/ADMIN special case)\n * @returns Permission check state and methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { can, isLoading, error } = useCan(userId, scope, 'read:users');\n *\n * if (isLoading) return <div>Checking permission...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return can ? <UserList /> : <div>Access denied</div>;\n * }\n * ```\n */\nexport function useCan(\n userId: UUID,\n scope: Scope,\n permission: Permission,\n pageId?: UUID,\n useCache: boolean = true,\n /**\n * Pre-computed super admin flag to avoid duplicate super admin checks.\n * Callers should check super admin once and pass the result to all useCan hooks.\n * Pass null if not checked yet, false/true if checked.\n * Defaults to null (not checked yet) - hook will check if needed.\n */\n precomputedSuperAdmin: boolean | null = null,\n appName?: string,\n) {\n // CRITICAL FIX: Initialize isSuperAdmin from precomputed value immediately\n // This prevents permission checks from running when we already know the user is a super admin\n // If precomputedSuperAdmin is true, we can immediately set can=true and isLoading=false\n const [isSuperAdmin, setIsSuperAdmin] = useState<boolean | null>(precomputedSuperAdmin ?? null);\n \n // For super admins, immediately grant permissions without waiting\n const initialCan = precomputedSuperAdmin === true ? true : false;\n const initialIsLoading = precomputedSuperAdmin === true ? false : true;\n \n const [can, setCan] = useState<boolean>(initialCan);\n const [isLoading, setIsLoading] = useState<boolean>(initialIsLoading);\n const [error, setError] = useState<Error | null>(null);\n\n // Validate scope parameter - handle undefined/null scope gracefully\n const isValidScope = scope && typeof scope === 'object';\n const organisationId = isValidScope ? scope.organisationId : undefined;\n const eventId = isValidScope ? scope.eventId : undefined;\n const appId = isValidScope ? scope.appId : undefined;\n\n // CRITICAL FIX: Immediately update state when precomputedSuperAdmin changes to true\n // This ensures super admins get immediate access without waiting for permission checks\n useEffect(() => {\n if (precomputedSuperAdmin === true && isSuperAdmin !== true) {\n setIsSuperAdmin(true);\n setCan(true);\n setIsLoading(false);\n setError(null);\n } else if (precomputedSuperAdmin === false && isSuperAdmin !== false) {\n setIsSuperAdmin(false);\n }\n }, [precomputedSuperAdmin, isSuperAdmin]);\n\n // Check super-admin status - super admins bypass organisation context requirements\n // PERFORMANCE OPTIMIZATION: Use precomputed value directly - no duplicate checks\n // Callers must check super admin once and pass the result (null if not checked yet)\n useEffect(() => {\n // If precomputed value is null, it means not checked yet - check ourselves\n if (precomputedSuperAdmin === null) {\n if (!userId) {\n setIsSuperAdmin(false);\n return;\n }\n\n let cancelled = false;\n const checkSuperAdmin = async () => {\n const startTime = Date.now();\n try {\n const { isSuperAdmin: checkSuperAdmin } = await import('../../api');\n\n // Add timeout warning\n const timeoutWarning = setTimeout(() => {\n if (!cancelled) {\n console.warn('[useCan] Super admin check taking longer than 5 seconds', {\n userId,\n elapsedMs: Date.now() - startTime,\n });\n }\n }, 5000);\n\n const isSuper = await checkSuperAdmin(userId);\n clearTimeout(timeoutWarning);\n\n if (!cancelled) {\n const elapsed = Date.now() - startTime;\n if (elapsed > 1000) {\n console.warn('[useCan] Super admin check took longer than expected', {\n userId,\n elapsedMs: elapsed,\n });\n }\n setIsSuperAdmin(isSuper);\n // If super admin, immediately grant permissions\n if (isSuper) {\n setCan(true);\n setIsLoading(false);\n setError(null);\n }\n }\n } catch (err) {\n if (!cancelled) {\n const elapsed = Date.now() - startTime;\n console.error('[useCan] Error checking super admin', {\n userId,\n error: err,\n elapsedMs: elapsed,\n });\n setIsSuperAdmin(false);\n }\n }\n };\n\n checkSuperAdmin();\n return () => {\n cancelled = true;\n };\n }\n }, [userId, precomputedSuperAdmin]);\n\n // Add timeout for missing organisation context (3 seconds)\n // Only apply timeout for resource-level permissions, not page-level (which can handle null orgs)\n // Super admins bypass this check\n useEffect(() => {\n const isPagePermission = permission.includes(':page.') || !!pageId;\n const requiresOrgId = !isPagePermission;\n\n // Don't block if user is super-admin (they bypass context requirements)\n if (isSuperAdmin === true) {\n return;\n }\n\n if (requiresOrgId && (!isValidScope || !organisationId || organisationId === null || (typeof organisationId === 'string' && organisationId.trim() === ''))) {\n const timeoutId = setTimeout(() => {\n setError(new Error('Organisation context is required for permission checks'));\n setIsLoading(false);\n setCan(false);\n }, 3000); // 3 seconds - typical permission check is < 1 second\n\n return () => clearTimeout(timeoutId);\n }\n // Clear error if organisation context becomes available\n if (error?.message === 'Organisation context is required for permission checks') {\n setError(null);\n }\n }, [isValidScope, organisationId, error, permission, pageId, isSuperAdmin]);\n\n // Use refs to track the last values to prevent unnecessary re-runs\n const lastUserIdRef = useRef<UUID | null>(null);\n const lastScopeRef = useRef<string | null>(null);\n const lastPermissionRef = useRef<Permission | null>(null);\n const lastPageIdRef = useRef<UUID | undefined | null>(null);\n const lastUseCacheRef = useRef<boolean | null>(null);\n const lastIsSuperAdminRef = useRef<boolean | null>(null);\n\n // Create a stable scope object for comparison\n const stableScope = useMemo(() => {\n if (!isValidScope) {\n return null;\n }\n return {\n organisationId,\n eventId,\n appId,\n };\n }, [isValidScope, organisationId, eventId, appId]);\n\n // Track previous scope for deep equality comparison\n const prevScopeRef = useRef<Scope | null>(null);\n\n useEffect(() => {\n // Use deep equality check for scope to prevent unnecessary re-runs\n const scopeChanged = !scopeEqual(prevScopeRef.current, stableScope);\n\n // Only run if something has actually changed\n // CRITICAL: Also check if isSuperAdmin changed - super admins bypass all checks\n const isSuperAdminChanged = lastIsSuperAdminRef.current !== isSuperAdmin;\n \n if (\n lastUserIdRef.current !== userId ||\n scopeChanged ||\n lastPermissionRef.current !== permission ||\n lastPageIdRef.current !== pageId ||\n lastUseCacheRef.current !== useCache ||\n isSuperAdminChanged\n ) {\n lastIsSuperAdminRef.current = isSuperAdmin;\n lastUserIdRef.current = userId;\n prevScopeRef.current = stableScope;\n lastPermissionRef.current = permission;\n lastPageIdRef.current = pageId;\n lastUseCacheRef.current = useCache;\n\n // Inline the permission check logic to avoid useCallback dependency issues\n const checkPermission = async () => {\n if (!userId) {\n setCan(false);\n setIsLoading(false);\n return;\n }\n\n // CRITICAL: Super admins bypass all permission checks - grant immediately\n // This must be checked BEFORE any other validation to avoid unnecessary API calls\n if (isSuperAdmin === true) {\n setCan(true);\n setIsLoading(false);\n setError(null);\n return;\n }\n\n // If super admin status is still being checked (null), wait for it to complete\n // Don't proceed with permission check until we know if user is super admin\n if (isSuperAdmin === null) {\n setIsLoading(true);\n setCan(false);\n setError(null);\n return;\n }\n\n // Validate scope before accessing properties\n if (!isValidScope) {\n setIsLoading(true);\n setCan(false);\n setError(null);\n // Timeout is handled in separate useEffect\n return;\n }\n\n // For page-level permissions, allow undefined/null organisationId (database function handles it)\n // For resource-level permissions, organisationId is required\n const isPagePermission = permission.includes(':page.') || !!pageId;\n const requiresOrgId = !isPagePermission;\n\n // Check if pageId is a pageName (not a UUID) - if so, we need appId to resolve it\n const isPageName = pageId && typeof pageId === 'string' && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(pageId);\n const needsAppIdForPageName = isPagePermission && isPageName;\n\n // Don't check permissions if scope is invalid and orgId is required\n // Wait for organisation context to resolve (unless it's a page permission that can handle null orgs)\n if (requiresOrgId && (!organisationId || organisationId === null || (typeof organisationId === 'string' && organisationId.trim() === ''))) {\n // Not super-admin (already checked above) - wait for org context\n setIsLoading(true);\n setCan(false);\n setError(null);\n // Timeout is handled in separate useEffect (Phase 1.4)\n return;\n }\n\n // For page-level permissions with pageName (not UUID), we need appId to resolve the pageName to pageId\n // Wait for appId to be available before checking permissions\n if (needsAppIdForPageName && (!appId || appId === null || (typeof appId === 'string' && appId.trim() === ''))) {\n setIsLoading(true);\n setCan(false);\n setError(null);\n // Will re-run when appId becomes available (via scope change detection)\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n // Create a valid scope object for the API call\n // For page-level permissions, organisationId can be undefined (database handles it)\n const validScope: Scope = {\n ...(organisationId ? { organisationId } : {}),\n ...(eventId ? { eventId } : {}),\n ...(appId ? { appId } : {})\n };\n\n // Pass super admin status to avoid duplicate check in isPermitted\n // Note: isPermittedCached doesn't support precomputedSuperAdmin, but the check will be cached\n // If we know user is NOT super admin (isSuperAdmin === false), pass false to skip the check\n const result = useCache\n ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName)\n : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, isSuperAdmin === false ? false : null);\n\n setCan(result);\n } catch (err) {\n const logger = getRBACLogger();\n logger.error('Permission check error:', { permission, error: err });\n console.error('[useCan] Permission check error', { userId, permission, error: err });\n setError(err instanceof Error ? err : new Error('Failed to check permission'));\n setCan(false);\n } finally {\n setIsLoading(false);\n }\n };\n\n checkPermission();\n }\n }, [userId, stableScope, permission, pageId, useCache, appName, isSuperAdmin]);\n\n const refetch = useCallback(async () => {\n if (!userId) {\n setCan(false);\n setIsLoading(false);\n return;\n }\n\n // Validate scope before accessing properties\n if (!isValidScope) {\n setCan(false);\n setIsLoading(true);\n setError(null);\n return;\n }\n\n // For page-level permissions, allow undefined/null organisationId (database function handles it)\n // For resource-level permissions, organisationId is required\n const isPagePermission = permission.includes(':page.') || !!pageId;\n const requiresOrgId = !isPagePermission;\n\n // Don't check permissions if scope is invalid and orgId is required\n if (requiresOrgId && (!organisationId || organisationId === null || (typeof organisationId === 'string' && organisationId.trim() === ''))) {\n setCan(false);\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n // Create a valid scope object for the API call\n // For page-level permissions, organisationId can be undefined (database handles it)\n const validScope: Scope = {\n ...(organisationId ? { organisationId } : {}),\n ...(eventId ? { eventId } : {}),\n ...(appId ? { appId } : {})\n };\n\n const result = useCache\n ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName)\n : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, null);\n\n setCan(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permission'));\n setCan(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, isValidScope, organisationId, eventId, appId, permission, pageId, useCache, appName]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n can,\n isLoading,\n error,\n refetch\n }), [can, isLoading, error, refetch]);\n}\n","/**\n * Deep equality check utility for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/Utils/DeepEqual\n * @since 2.0.0\n * \n * Provides deep equality checking for scope objects and other RBAC data structures.\n */\n\nimport { Scope } from '../types';\n\n/**\n * Deep equality check for two values\n * \n * @param a - First value\n * @param b - Second value\n * @returns True if values are deeply equal\n */\nexport function deepEqual(a: unknown, b: unknown): boolean {\n if (a === b) {\n return true;\n }\n\n if (a == null || b == null) {\n return a === b;\n }\n\n if (typeof a !== typeof b) {\n return false;\n }\n\n if (typeof a !== 'object') {\n return false;\n }\n\n if (Array.isArray(a) !== Array.isArray(b)) {\n return false;\n }\n\n if (Array.isArray(a) && Array.isArray(b)) {\n if (a.length !== b.length) {\n return false;\n }\n for (let i = 0; i < a.length; i++) {\n if (!deepEqual(a[i], b[i])) {\n return false;\n }\n }\n return true;\n }\n\n const keysA = Object.keys(a as Record<string, unknown>);\n const keysB = Object.keys(b as Record<string, unknown>);\n\n if (keysA.length !== keysB.length) {\n return false;\n }\n\n for (const key of keysA) {\n if (!keysB.includes(key)) {\n return false;\n }\n if (!deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])) {\n return false;\n }\n }\n\n return true;\n}\n\n/**\n * Deep equality check for Scope objects\n * \n * @param a - First scope\n * @param b - Second scope\n * @returns True if scopes are deeply equal\n */\nexport function scopeEqual(a: Scope | null | undefined, b: Scope | null | undefined): boolean {\n if (a === b) {\n return true;\n }\n\n if (a == null || b == null) {\n return a === b;\n }\n\n return (\n a.organisationId === b.organisationId &&\n a.eventId === b.eventId &&\n a.appId === b.appId\n );\n}\n\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { isPermitted, isPermittedCached } from '../../api';\nimport { Permission, Scope, UUID } from '../../types';\n\n/**\n * Hook to check if user has all of the specified permissions\n *\n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Whether user has all of the permissions\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { hasAll, isLoading, error } = useHasAllPermissions(\n * userId,\n * scope,\n * ['read:users', 'create:users', 'update:users']\n * );\n *\n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return hasAll ? <FullUserManagementPanel /> : <div>Insufficient permissions</div>;\n * }\n * ```\n */\nexport function useHasAllPermissions(\n userId: UUID,\n scope: Scope,\n permissions: Permission[],\n useCache: boolean = true\n): {\n hasAll: boolean;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [hasAll, setHasAll] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkAllPermissions = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setHasAll(false);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n let hasAllPermissions = true;\n\n for (const permission of permissions) {\n const result = useCache\n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n\n if (!result) {\n hasAllPermissions = false;\n break;\n }\n }\n\n setHasAll(hasAllPermissions);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setHasAll(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkAllPermissions();\n }, [checkAllPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n hasAll,\n isLoading,\n error,\n refetch: checkAllPermissions\n }), [hasAll, isLoading, error, checkAllPermissions]);\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { isPermitted, isPermittedCached } from '../../api';\nimport { Permission, Scope, UUID } from '../../types';\n\n/**\n * Hook to check if user has any of the specified permissions\n *\n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Whether user has any of the permissions\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { hasAny, isLoading, error } = useHasAnyPermission(\n * userId,\n * scope,\n * ['read:users', 'create:users']\n * );\n *\n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return hasAny ? <UserManagementPanel /> : <div>No user permissions</div>;\n * }\n * ```\n */\nexport function useHasAnyPermission(\n userId: UUID,\n scope: Scope,\n permissions: Permission[],\n useCache: boolean = true\n): {\n hasAny: boolean;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [hasAny, setHasAny] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkAnyPermission = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setHasAny(false);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n let hasAnyPermission = false;\n\n for (const permission of permissions) {\n const result = useCache\n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n\n if (result) {\n hasAnyPermission = true;\n break;\n }\n }\n\n setHasAny(hasAnyPermission);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setHasAny(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkAnyPermission();\n }, [checkAnyPermission]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n hasAny,\n isLoading,\n error,\n refetch: checkAnyPermission\n }), [hasAny, isLoading, error, checkAnyPermission]);\n}\n","import { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { isPermitted, isPermittedCached } from '../../api';\nimport { Permission, Scope, UUID } from '../../types';\n\n/**\n * Hook to check multiple permissions at once\n *\n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Multiple permission check results\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { results, isLoading, error } = useMultiplePermissions(\n * userId,\n * scope,\n * ['read:users', 'create:users', 'update:users']\n * );\n *\n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * {results['read:users'] && <UserList />}\n * {results['create:users'] && <CreateUserButton />}\n * {results['update:users'] && <EditUserButton />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useMultiplePermissions(\n userId: UUID,\n scope: Scope,\n permissions: Permission[],\n useCache: boolean = true\n): {\n results: Record<Permission, boolean>;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [results, setResults] = useState<Record<Permission, boolean>>({} as Record<Permission, boolean>);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkPermissions = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setResults({} as Record<Permission, boolean>);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n const permissionResults: Record<Permission, boolean> = {} as Record<Permission, boolean>;\n\n // Check each permission\n for (const permission of permissions) {\n const result = useCache\n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n permissionResults[permission] = result;\n }\n\n setResults(permissionResults);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setResults({} as Record<Permission, boolean>);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkPermissions();\n }, [checkPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n results,\n isLoading,\n error,\n refetch: checkPermissions\n }), [results, isLoading, error, checkPermissions]);\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from 'react';\n\nimport { Permission, PermissionMap, Scope, UUID } from '../../types';\nimport { getPermissionMap } from '../../api';\nimport { getRBACLogger } from '../../config';\n\n/**\n * Hook to get user's permissions in a scope\n *\n * @param userId - User ID\n * @param organisationId - Organisation ID\n * @param eventId - Event ID (optional)\n * @param appId - Application ID (optional)\n * @returns Permission state and methods\n *\n * @example\n * ```tsx\n * function MyComponent() {\n * const { permissions, isLoading, error } = usePermissions(\n * userId,\n * organisationId,\n * eventId,\n * appId\n * );\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n *\n * return (\n * <div>\n * {permissions['read:users'] && <UserList />}\n * {permissions['create:users'] && <CreateUserButton />}\n * </div>\n * );\n * }\n * ```\n */\nexport function usePermissions(\n userId: UUID,\n organisationId: string | undefined,\n eventId: string | undefined,\n appId: string | undefined\n) {\n const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [fetchTrigger, setFetchTrigger] = useState(0);\n const isFetchingRef = useRef(false);\n const logger = getRBACLogger();\n\n // Track previous values to detect changes imperatively\n const prevValuesRef = useRef({ userId, organisationId, eventId, appId });\n\n // Normalize organisationId to empty string if undefined\n const orgId = organisationId || '';\n\n // Add timeout for missing organisation context (3 seconds)\n // OPTIMIZATION: Skip timeout if userId is null/undefined (indicates pre-filtered mode)\n useEffect(() => {\n // If userId is null/undefined, skip the timeout - this indicates items are pre-filtered\n // and we don't need to wait for organisation context\n if (!userId) {\n return; // Skip timeout when userId is null (pre-filtered mode)\n }\n\n if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {\n const timeoutId = setTimeout(() => {\n setError(new Error('Organisation context is required for permission checks'));\n setIsLoading(false);\n }, 3000); // 3 seconds - typical permission check is < 1 second\n\n return () => clearTimeout(timeoutId);\n }\n // Clear error if organisation context becomes available\n if (error?.message === 'Organisation context is required for permission checks') {\n setError(null);\n }\n }, [userId, organisationId, error, orgId]);\n\n // CRITICAL: Detect parameter changes and trigger fetch\n // Moved to useEffect to prevent render-time state updates that could cause render loops\n useEffect(() => {\n const paramsChanged =\n prevValuesRef.current.userId !== userId ||\n prevValuesRef.current.organisationId !== organisationId ||\n prevValuesRef.current.eventId !== eventId ||\n prevValuesRef.current.appId !== appId;\n\n if (paramsChanged) {\n // Only log significant changes (appId changes are most important)\n if (prevValuesRef.current.appId !== appId) {\n // AppId changed - triggering fetch\n }\n prevValuesRef.current = { userId, organisationId, eventId, appId };\n // Increment counter to force fetch useEffect to run\n setFetchTrigger(prev => prev + 1);\n }\n }, [userId, organisationId, eventId, appId, logger]);\n\n useEffect(() => {\n const fetchPermissions = async () => {\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n return;\n }\n\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n // Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)\n // Wait for organisation context to resolve\n // IMPORTANT: Don't clear existing permissions here - keep them until we have new ones\n // OPTIMIZATION: If userId is null/undefined, immediately set loading to false\n // This indicates pre-filtered mode where we don't need to wait for organisation context\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {\n // Keep existing permissions, just mark as loading\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n isFetchingRef.current = true;\n setIsLoading(true);\n setError(null);\n\n // Build scope object for API call\n const scope: Scope = {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n };\n\n // Fetch new permissions - don't clear old ones until we have new ones\n const permissionMap = await getPermissionMap({ userId, scope });\n\n // Only log if there's a significant change or error\n const permissionCount = Object.keys(permissionMap).length;\n if (permissionCount === 0 && Object.keys(permissions).length > 0) {\n logger.warn('[usePermissions] Permissions fetched but returned empty map', {\n scope: { organisationId: orgId, eventId, appId }\n });\n }\n\n // Only update permissions if fetch was successful\n setPermissions(permissionMap);\n } catch (err) {\n // On error, keep existing permissions but set error state\n // This prevents the UI from losing all items when there's a transient error\n logger.error('[usePermissions] Failed to fetch permissions:', err);\n setError(err instanceof Error ? err : new Error('Failed to fetch permissions'));\n // Don't clear permissions on error - keep what we had\n } finally {\n setIsLoading(false);\n isFetchingRef.current = false;\n }\n };\n\n fetchPermissions();\n }, [fetchTrigger, userId, organisationId, eventId, appId]);\n\n const hasPermission = useCallback((permission: Permission): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissions[permission] === true;\n }, [permissions]);\n\n const hasAnyPermission = useCallback((permissionList: Permission[]): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissionList.some(p => permissions[p] === true);\n }, [permissions]);\n\n const hasAllPermissions = useCallback((permissionList: Permission[]): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissionList.every(p => permissions[p] === true);\n }, [permissions]);\n\n const refetch = useCallback(async () => {\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n return;\n }\n\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n // Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)\n // IMPORTANT: Don't clear existing permissions - keep them until we have new ones\n if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {\n // Keep existing permissions, just mark as loading\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n isFetchingRef.current = true;\n setIsLoading(true);\n setError(null);\n\n // Build scope object for API call\n const scope: Scope = {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n };\n\n // Fetch new permissions - don't clear old ones until we have new ones\n const permissionMap = await getPermissionMap({ userId, scope });\n\n // Only update permissions if fetch was successful\n setPermissions(permissionMap);\n } catch (err) {\n // On error, keep existing permissions but set error state\n // This prevents the UI from losing all items when there's a transient error\n const logger = getRBACLogger();\n logger.error('Failed to refetch permissions:', err);\n setError(err instanceof Error ? err : new Error('Failed to fetch permissions'));\n // Don't clear permissions on error - keep what we had\n } finally {\n setIsLoading(false);\n isFetchingRef.current = false;\n }\n }, [userId, organisationId, eventId, appId]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n permissions,\n isLoading,\n error,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n refetch\n }), [permissions, isLoading, error, hasPermission, hasAnyPermission, hasAllPermissions, refetch]);\n}\n","/**\n * @file useResourcePermissions Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * Hook to check permissions for a specific resource type.\n * This hook centralizes the common pattern of checking create/update/delete/read\n * permissions, eliminating ~30 lines of boilerplate code per hook usage.\n * \n * @example\n * ```tsx\n * import { useResourcePermissions } from '@jmruthers/pace-core/rbac';\n * \n * function ContactsHook() {\n * const { canCreate, canUpdate, canDelete } = useResourcePermissions('contacts');\n * \n * const addContact = async (data: ContactData) => {\n * if (!canCreate('contacts')) {\n * throw new Error(\"Permission denied: You do not have permission to create contacts.\");\n * }\n * // ... perform mutation\n * };\n * }\n * ```\n * \n * @example\n * ```tsx\n * // With read permissions enabled\n * const { canRead } = useResourcePermissions('contacts', { enableRead: true });\n * \n * if (!canRead('contacts')) {\n * return <PermissionDenied />;\n * }\n * ```\n * \n * @security\n * - Requires organisation context (handled by useResolvedScope)\n * - All permission checks are scoped to the current organisation/event/app context\n * - Missing user context results in all permissions being denied\n */\n\nimport { useMemo } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useResolvedScope } from './useResolvedScope';\nimport { useCan } from './usePermissions';\nimport type { Scope, Permission } from '../types';\n\nexport interface UseResourcePermissionsOptions {\n /** Whether to check read permissions (default: false) */\n enableRead?: boolean;\n /** Whether scope resolution is required (default: true) */\n requireScope?: boolean;\n}\n\nexport interface ResourcePermissions {\n /** Check if user can create resources of this type */\n canCreate: (resource: string) => boolean;\n /** Check if user can update resources of this type */\n canUpdate: (resource: string) => boolean;\n /** Check if user can delete resources of this type */\n canDelete: (resource: string) => boolean;\n /** Check if user can read resources of this type */\n canRead: (resource: string) => boolean;\n /** The resolved scope object (for advanced use cases) */\n scope: Scope;\n /** Whether any permission check is currently loading */\n isLoading: boolean;\n /** Error from any permission check or scope resolution */\n error: Error | null;\n}\n\n/**\n * Hook to check permissions for a specific resource\n * \n * This hook encapsulates the common pattern of checking create/update/delete/read\n * permissions for a resource type. It handles scope resolution, user context,\n * and provides a simple API for permission checking.\n * \n * **Page Permission Support:**\n * When an `appId` is available in the resolved scope, the hook automatically:\n * 1. Waits for scope resolution to complete (including `appId` being set)\n * 2. Constructs permission strings with the `page.` prefix (e.g., `create:page.planning`)\n * 3. Passes the resource name as `pageId` to enable page-based permission checks\n * \n * This ensures permission strings match the format returned by `rbac_permissions_get`\n * (e.g., `create:page.planning`) rather than resource-based format (e.g., `create:planning`).\n * \n * **Scope Resolution Timing:**\n * The hook waits for scope resolution to complete before constructing permission strings.\n * This prevents timing issues where permission checks use the wrong format (e.g., `delete:planning`\n * instead of `delete:page.planning`) when `appId` is not yet available in the scope.\n * \n * The RPC function `rbac_check_permission_simplified` will resolve the page name to a page ID\n * and check page permissions if the resource matches a registered page in `rbac_app_pages`.\n * If the resource is not a registered page, it will fall back to resource-based permission checking.\n * \n * @param resource - The resource name (e.g., 'contacts', 'risks', 'planning')\n * Can be a resource name or a page name registered in rbac_app_pages\n * @param options - Optional configuration\n * @param options.enableRead - Whether to check read permissions (default: false)\n * @param options.requireScope - Whether scope resolution is required (default: true)\n * @returns Object with permission check functions and scope\n * \n * @example\n * ```tsx\n * function useContacts() {\n * const { canCreate, canUpdate, canDelete } = useResourcePermissions('contacts');\n * \n * const addContact = async (data: ContactData) => {\n * if (!canCreate('contacts')) {\n * throw new Error(\"Permission denied\");\n * }\n * // ... perform mutation\n * };\n * }\n * ```\n * \n * @example\n * ```tsx\n * // Works with page names when appId is available in scope\n * function usePlanning() {\n * const { canCreate, canUpdate, canDelete } = useResourcePermissions('planning');\n * \n * // Will check page permissions if 'planning' is registered in rbac_app_pages\n * // Falls back to resource permissions if not a registered page\n * const deleteItem = async (id: string) => {\n * if (!canDelete('planning')) {\n * throw new Error(\"Permission denied\");\n * }\n * // ... perform deletion\n * };\n * }\n * ```\n */\nexport function useResourcePermissions(\n resource: string,\n options: UseResourcePermissionsOptions = {}\n): ResourcePermissions {\n const { enableRead = false, requireScope = true } = options;\n\n // Get user and supabase client from UnifiedAuth\n const { user, supabase } = useUnifiedAuth();\n \n // Get selected organisation\n const { selectedOrganisation } = useOrganisations();\n \n // Get selected event (optional - wrap in try/catch)\n let selectedEvent: { event_id: string } | null = null;\n try {\n const eventsContext = useEvents();\n selectedEvent = eventsContext.selectedEvent;\n } catch (error) {\n // Event provider not available - continue without event context\n // This is expected in some apps that don't use events\n }\n\n // Resolve scope for permission checks\n const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({\n supabase,\n selectedOrganisationId: selectedOrganisation?.id || null,\n selectedEventId: selectedEvent?.event_id || null\n });\n\n // CRITICAL FIX: Only use resolvedScope when it's available (not during loading)\n // This ensures we wait for appId to be resolved before constructing permission strings\n // If resolvedScope is null (still loading), we can't determine if we should use page permissions\n // so we must wait for scope resolution to complete\n const scope: Scope = resolvedScope || {\n organisationId: selectedOrganisation?.id || '',\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n\n // CRITICAL FIX: Only use page permissions when appId is actually available in resolvedScope\n // If scope is still loading (resolvedScope is null), we can't know if appId will be available\n // so we must wait for scope resolution before constructing page permission strings\n // This prevents using wrong permission format (delete:planning instead of delete:page.planning)\n const hasAppId = !!resolvedScope?.appId;\n const pageId = hasAppId ? resource : undefined;\n \n // When appId is available in resolved scope, construct permission strings with page. prefix\n // This matches the format that rbac_permissions_get returns (e.g., 'create:page.planning')\n // and ensures consistent permission checking for page-based resources\n // IMPORTANT: Only use page format when appId is actually resolved, not during loading\n const isPagePermission = hasAppId && !!pageId;\n const createPermission = isPagePermission ? `create:page.${resource}` : `create:${resource}`;\n const updatePermission = isPagePermission ? `update:page.${resource}` : `update:${resource}`;\n const deletePermission = isPagePermission ? `delete:page.${resource}` : `delete:${resource}`;\n const readPermission = isPagePermission ? `read:page.${resource}` : `read:${resource}`;\n\n // Permission checks for create, update, delete\n // Pass null for super admin status (not checked yet - hook will check if needed)\n // PERFORMANCE: These hooks will each check super admin separately - could be optimized in future\n // CRITICAL: useCan will wait for appId when pageId is provided (it checks needsAppIdForPageName)\n // But we must ensure permission strings are correct before calling useCan\n const { can: canCreateResult, isLoading: createLoading, error: createError } = useCan(\n user?.id || '',\n scope,\n createPermission as Permission,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true, // useCache\n null, // precomputedSuperAdmin - not checked yet\n undefined // appName\n );\n\n const { can: canUpdateResult, isLoading: updateLoading, error: updateError } = useCan(\n user?.id || '',\n scope,\n updatePermission as Permission,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true, // useCache\n null, // precomputedSuperAdmin - not checked yet\n undefined // appName\n );\n\n const { can: canDeleteResult, isLoading: deleteLoading, error: deleteError } = useCan(\n user?.id || '',\n scope,\n deletePermission as Permission,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true, // useCache\n null, // precomputedSuperAdmin - not checked yet\n undefined // appName\n );\n\n // Optional read permission check\n const { can: canReadResult, isLoading: readLoading, error: readError } = useCan(\n user?.id || '',\n scope,\n readPermission as Permission,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true, // useCache\n null, // precomputedSuperAdmin - not checked yet\n undefined // appName\n );\n\n // Aggregate loading states - any permission check or scope resolution loading\n // CRITICAL: When requireScope is true, we must wait for scope resolution to complete\n // so we can determine the correct permission format (page vs resource permissions)\n // This prevents using wrong permission format (delete:planning instead of delete:page.planning)\n const isLoading = useMemo(() => {\n // If scope resolution is required, wait for it to complete\n const waitingForScope = requireScope && scopeLoading;\n return waitingForScope || createLoading || updateLoading || deleteLoading || (enableRead && readLoading);\n }, [scopeLoading, requireScope, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);\n\n // Aggregate errors - prefer scope error, then any permission error\n const error = useMemo(() => {\n if (scopeError) return scopeError;\n if (createError) return createError;\n if (updateError) return updateError;\n if (deleteError) return deleteError;\n if (enableRead && readError) return readError;\n return null;\n }, [scopeError, createError, updateError, deleteError, readError, enableRead]);\n\n // Return wrapper functions that take resource name and return permission result\n // Note: The resource parameter in the function is for consistency with the API,\n // but we're checking permissions for the resource passed to the hook\n return useMemo(() => ({\n canCreate: (res: string) => {\n // For now, we only check the resource passed to the hook\n // Future enhancement could support checking different resources\n if (res !== resource) {\n return false;\n }\n return canCreateResult; // canCreateResult is already the boolean 'can' value from useCan\n },\n canUpdate: (res: string) => {\n if (res !== resource) {\n return false;\n }\n return canUpdateResult; // canUpdateResult is already the boolean 'can' value from useCan\n },\n canDelete: (res: string) => {\n if (res !== resource) {\n return false;\n }\n return canDeleteResult; // canDeleteResult is already the boolean 'can' value from useCan\n },\n canRead: (res: string) => {\n if (!enableRead) {\n return true; // If read checking is disabled, allow read\n }\n if (res !== resource) {\n return false;\n }\n return canReadResult; // canReadResult is already the boolean 'can' value from useCan\n },\n scope,\n isLoading,\n error\n }), [\n resource,\n canCreateResult, // This is already the boolean 'can' value\n canUpdateResult, // This is already the boolean 'can' value\n canDeleteResult, // This is already the boolean 'can' value\n canReadResult, // This is already the boolean 'can' value\n enableRead,\n scope,\n isLoading,\n error\n ]);\n}\n\n","/**\n * @file RBAC Role Management Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 2.1.0\n *\n * React hook for managing RBAC roles safely using RPC functions.\n * This hook provides a secure, type-safe interface for granting and revoking roles\n * that ensures proper audit trails and security checks.\n *\n * @example\n * ```tsx\n * import { useRoleManagement } from '@jmruthers/pace-core/rbac';\n *\n * function UserRolesComponent() {\n * const { \n * revokeEventAppRole, \n * grantEventAppRole,\n * grantGlobalRole,\n * revokeGlobalRole,\n * grantOrganisationRole,\n * revokeOrganisationRole,\n * isLoading, \n * error \n * } = useRoleManagement();\n *\n * // Grant a global role\n * const handleGrantGlobalRole = async () => {\n * const result = await grantGlobalRole({\n * user_id: userId,\n * role: 'super_admin'\n * });\n * if (result.success) {\n * toast({ title: 'Role granted successfully' });\n * }\n * };\n *\n * // Grant an organisation role\n * const handleGrantOrgRole = async () => {\n * const result = await grantOrganisationRole({\n * user_id: userId,\n * organisation_id: orgId,\n * role: 'org_admin'\n * });\n * if (result.success) {\n * toast({ title: 'Role granted successfully' });\n * }\n * };\n *\n * return (\n * <div>\n * <button onClick={handleGrantGlobalRole}>Grant Super Admin</button>\n * <button onClick={handleGrantOrgRole}>Grant Org Admin</button>\n * </div>\n * );\n * }\n * ```\n */\n\nimport { useState, useCallback } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport type { UUID } from '../types';\n\nexport interface EventAppRoleData {\n user_id: UUID;\n organisation_id: UUID;\n event_id: string;\n app_id: UUID;\n role: 'viewer' | 'participant' | 'planner' | 'event_admin';\n}\n\nexport interface OrganisationRoleData {\n user_id: UUID;\n organisation_id: UUID;\n role: 'supporter' | 'member' | 'leader' | 'org_admin';\n}\n\nexport interface GlobalRoleData {\n user_id: UUID;\n role: 'super_admin';\n}\n\nexport interface RevokeEventAppRoleParams extends EventAppRoleData {\n revoked_by?: UUID;\n}\n\nexport interface GrantEventAppRoleParams extends EventAppRoleData {\n granted_by?: UUID;\n valid_from?: string;\n valid_to?: string | null;\n}\n\nexport interface RevokeOrganisationRoleParams extends OrganisationRoleData {\n revoked_by?: UUID;\n}\n\nexport interface GrantOrganisationRoleParams extends OrganisationRoleData {\n granted_by?: UUID;\n valid_from?: string;\n valid_to?: string | null;\n}\n\nexport interface RevokeGlobalRoleParams extends GlobalRoleData {\n revoked_by?: UUID;\n}\n\nexport interface GrantGlobalRoleParams extends GlobalRoleData {\n granted_by?: UUID;\n valid_from?: string;\n valid_to?: string | null;\n}\n\nexport interface RoleManagementResult {\n success: boolean;\n message?: string;\n error?: string;\n roleId?: UUID;\n}\n\nexport function useRoleManagement() {\n const { user, supabase } = useUnifiedAuth();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n if (!supabase) {\n throw new Error('useRoleManagement requires a Supabase client. Ensure UnifiedAuthProvider is configured.');\n }\n\n /**\n * Revoke an event app role using the secure RPC function\n * \n * This function uses the `revoke_event_app_role` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (revoked_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role revocation parameters\n * @returns Promise resolving to operation result\n */\n const revokeEventAppRole = useCallback(async (\n params: RevokeEventAppRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('revoke_event_app_role', {\n p_user_id: params.user_id,\n p_organisation_id: params.organisation_id,\n p_event_id: params.event_id,\n p_app_id: params.app_id,\n p_role: params.role,\n p_revoked_by: params.revoked_by || user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to revoke role');\n }\n\n return {\n success: data === true,\n message: data === true ? 'Role revoked successfully' : 'No role found to revoke',\n error: data === false ? 'No matching role found' : undefined\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id]);\n\n /**\n * Grant an event app role using the secure RPC function\n * \n * This function uses the `grant_event_app_role` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (granted_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role grant parameters\n * @returns Promise resolving to operation result with role ID\n */\n const grantEventAppRole = useCallback(async (\n params: GrantEventAppRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('grant_event_app_role', {\n p_user_id: params.user_id,\n p_organisation_id: params.organisation_id,\n p_event_id: params.event_id,\n p_app_id: params.app_id,\n p_role: params.role,\n p_granted_by: params.granted_by || user?.id || undefined,\n p_valid_from: params.valid_from,\n p_valid_to: params.valid_to\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to grant role');\n }\n\n if (!data) {\n return {\n success: false,\n error: 'Failed to grant role - no role ID returned'\n };\n }\n\n return {\n success: true,\n message: 'Role granted successfully',\n roleId: data as UUID\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id]);\n\n /**\n * Revoke an event app role by role ID (alternative method)\n * \n * This fetches the role by ID first to get the required context (role name, event_id, app_id),\n * then uses the unified `rbac_role_revoke` function to revoke it.\n * \n * @param roleId - The role ID to revoke\n * @returns Promise resolving to operation result\n */\n const revokeRoleById = useCallback(async (\n roleId: UUID\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n // First, fetch the role by ID to get the required context\n const { data: roleData, error: fetchError } = await supabase\n .from('rbac_event_app_roles')\n .select('user_id, role, event_id, app_id')\n .eq('id', roleId)\n .single();\n\n if (fetchError || !roleData) {\n throw new Error(fetchError?.message || 'Role not found');\n }\n\n // Construct context_id in the format required by rbac_role_revoke: \"event_id:app_id\"\n const contextId = `${roleData.event_id}:${roleData.app_id}`;\n\n // Now call rbac_role_revoke with the required parameters\n const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', {\n p_user_id: roleData.user_id,\n p_role_type: 'event_app',\n p_role_name: roleData.role,\n p_context_id: contextId,\n p_revoked_by: user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to revoke role');\n }\n\n // rbac_role_revoke returns a table with success, message, revoked_count, error_code\n const result = Array.isArray(data) && data.length > 0 ? data[0] : null;\n\n return {\n success: result?.success === true,\n message: result?.message || undefined,\n error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id, supabase]);\n\n /**\n * Grant a global role using the unified RPC function\n * \n * This function uses the `rbac_role_grant` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (granted_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role grant parameters\n * @returns Promise resolving to operation result with role ID\n */\n const grantGlobalRole = useCallback(async (\n params: GrantGlobalRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('rbac_role_grant', {\n p_user_id: params.user_id,\n p_role_type: 'global',\n p_role_name: params.role,\n p_context_id: null, // Global roles don't need context\n p_granted_by: params.granted_by || user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to grant role');\n }\n\n // rbac_role_grant returns a table with success, message, role_id, error_code\n const result = Array.isArray(data) && data.length > 0 ? data[0] : null;\n\n if (!result || !result.success) {\n return {\n success: false,\n error: result?.message || result?.error_code || 'Failed to grant role',\n message: result?.message\n };\n }\n\n return {\n success: true,\n message: result.message || 'Role granted successfully',\n roleId: result.role_id\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id, supabase]);\n\n /**\n * Revoke a global role using the unified RPC function\n * \n * This function uses the `rbac_role_revoke` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (revoked_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role revocation parameters\n * @returns Promise resolving to operation result\n */\n const revokeGlobalRole = useCallback(async (\n params: RevokeGlobalRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', {\n p_user_id: params.user_id,\n p_role_type: 'global',\n p_role_name: params.role,\n p_context_id: null, // Global roles don't need context\n p_revoked_by: params.revoked_by || user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to revoke role');\n }\n\n // rbac_role_revoke returns a table with success, message, revoked_count, error_code\n const result = Array.isArray(data) && data.length > 0 ? data[0] : null;\n\n return {\n success: result?.success === true,\n message: result?.message || undefined,\n error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id, supabase]);\n\n /**\n * Grant an organisation role using the unified RPC function\n * \n * This function uses the `rbac_role_grant` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (granted_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role grant parameters\n * @returns Promise resolving to operation result with role ID\n */\n const grantOrganisationRole = useCallback(async (\n params: GrantOrganisationRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('rbac_role_grant', {\n p_user_id: params.user_id,\n p_role_type: 'organisation',\n p_role_name: params.role,\n p_context_id: params.organisation_id, // Organisation ID as context\n p_granted_by: params.granted_by || user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to grant role');\n }\n\n // rbac_role_grant returns a table with success, message, role_id, error_code\n const result = Array.isArray(data) && data.length > 0 ? data[0] : null;\n\n if (!result || !result.success) {\n return {\n success: false,\n error: result?.message || result?.error_code || 'Failed to grant role',\n message: result?.message\n };\n }\n\n return {\n success: true,\n message: result.message || 'Role granted successfully',\n roleId: result.role_id\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id, supabase]);\n\n /**\n * Revoke an organisation role using the unified RPC function\n * \n * This function uses the `rbac_role_revoke` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (revoked_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role revocation parameters\n * @returns Promise resolving to operation result\n */\n const revokeOrganisationRole = useCallback(async (\n params: RevokeOrganisationRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', {\n p_user_id: params.user_id,\n p_role_type: 'organisation',\n p_role_name: params.role,\n p_context_id: params.organisation_id, // Organisation ID as context\n p_revoked_by: params.revoked_by || user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to revoke role');\n }\n\n // rbac_role_revoke returns a table with success, message, revoked_count, error_code\n const result = Array.isArray(data) && data.length > 0 ? data[0] : null;\n\n return {\n success: result?.success === true,\n message: result?.message || undefined,\n error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id, supabase]);\n\n return {\n // Event app roles (existing)\n revokeEventAppRole,\n grantEventAppRole,\n revokeRoleById,\n // Global roles (new)\n grantGlobalRole,\n revokeGlobalRole,\n // Organisation roles (new)\n grantOrganisationRole,\n revokeOrganisationRole,\n // Shared state\n isLoading,\n error\n };\n}\n\n","/**\n * @file Secure Supabase Client Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n *\n * React hook for getting a secure Supabase client with automatic context injection\n * and caching to prevent multiple client instances.\n *\n * ## Overview\n *\n * This hook provides a secure Supabase client that automatically injects\n * organisation and event context for all database operations, while preventing\n * the creation of multiple Supabase client instances (which causes the\n * \"Multiple GoTrueClient instances\" warning).\n *\n * ## Features\n *\n * - **Automatic Context Injection**: Organisation, event, and app context are\n * automatically injected into all database queries\n * - **Client Instance Caching**: Prevents creating duplicate Supabase clients\n * for the same context, eliminating the \"Multiple GoTrueClient instances\" warning\n * - **Automatic Fallback**: Falls back to base client when context is unavailable\n * - **Type-Safe**: Full TypeScript support with proper type inference\n *\n * ## Usage\n *\n * ### Basic Usage\n *\n * ```tsx\n * import { useSecureSupabase } from '@jmruthers/pace-core/rbac';\n *\n * function MyComponent() {\n * const supabase = useSecureSupabase();\n *\n * if (!supabase) {\n * return <div>Loading context...</div>;\n * }\n *\n * const fetchData = async () => {\n * const { data, error } = await supabase\n * .from('users')\n * .select('*');\n * // Organisation context is automatically injected\n * };\n *\n * return <div>...</div>;\n * }\n * ```\n *\n * ### With Base Client Fallback\n *\n * ```tsx\n * import { useSecureSupabase } from '@jmruthers/pace-core/rbac';\n * import { supabase } from './lib/supabase';\n *\n * function MyComponent() {\n * // Provide base client as fallback\n * const secureSupabase = useSecureSupabase(supabase);\n *\n * // secureSupabase will be the secure client when context is available,\n * // or the base client when context is unavailable\n * }\n * ```\n *\n * ## How It Works\n *\n * 1. **Context Resolution**: The hook uses `useResolvedScope` to get the current\n * organisation, event, and app context\n * 2. **Client Caching**: Clients are cached by context key (organisationId-eventId-appId)\n * to prevent duplicate instances\n * 3. **Automatic Injection**: The secure client automatically injects context headers\n * into all database operations\n * 4. **Fallback Behavior**: When context is unavailable or event is loading, the hook\n * returns the base client (or null if no base client provided)\n *\n * ## Security\n *\n * - **Organisation Context Enforcement**: All queries automatically include organisation\n * context, preventing cross-organisation data access\n * - **Event Context Injection**: Event context is automatically included when available\n * - **App Context Support**: App context is included when resolved from scope\n *\n * ## Performance\n *\n * - **Client Instance Caching**: Prevents creating multiple Supabase clients for the\n * same context, reducing memory usage and eliminating the \"Multiple GoTrueClient\n * instances\" warning\n * - **Cache Management**: Automatically cleans up old cache entries (keeps last 5)\n * to prevent memory leaks\n * - **Stable References**: Returns stable client references to prevent unnecessary\n * re-renders in consuming components\n *\n * ## Requirements\n *\n * - Must be used within `UnifiedAuthProvider` context\n * - Requires `useOrganisations` and `useEvents` hooks to be available\n * - Environment variables `VITE_SUPABASE_URL` and `VITE_SUPABASE_PUBLISHABLE_KEY` must be set\n * (or `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` for Next.js)\n *\n * ## See Also\n *\n * - {@link SecureSupabaseClient} - The underlying secure client class\n * - {@link createSecureClient} - Function to create secure clients manually\n * - {@link useResolvedScope} - Hook for resolving RBAC scope\n *\n * @security\n * - Enforces organisation context on all queries\n * - Prevents cross-organisation data access\n * - Automatic context injection\n *\n * @performance\n * - Client instance caching prevents duplicate creation\n * - Reuses cached clients for same context\n * - Automatic cache cleanup\n */\n\nimport { useMemo, useRef } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useResolvedScope } from './useResolvedScope';\nimport { useOrganisationSecurity } from '../../hooks/useOrganisationSecurity';\nimport { createSecureClient, fromSupabaseClient, SecureSupabaseClient } from '../secureClient';\nimport type { Database } from '../../types/database';\nimport type { SupabaseClient } from '@supabase/supabase-js';\nimport { logger } from '../../utils/core/logger';\n\n// Cache secure clients by context to prevent creating multiple instances\n// This prevents the \"Multiple GoTrueClient instances\" warning\nconst secureClientCache = new Map<string, SecureSupabaseClient>();\n\n// Maximum cache size to prevent memory leaks\nconst MAX_CACHE_SIZE = 5;\n\n/**\n * Get cache key for secure client based on context\n * CRITICAL: Must include isSuperAdmin in cache key to ensure correct filtering behavior\n */\nfunction getCacheKey(\n organisationId: string | null | undefined,\n eventId: string | undefined,\n appId: string | undefined,\n isSuperAdmin: boolean\n): string {\n return `${organisationId || 'no-org'}-${eventId || 'no-event'}-${appId || 'no-app'}-${isSuperAdmin ? 'super' : 'regular'}`;\n}\n\n/**\n * Get Supabase URL and key from environment\n */\nfunction getSupabaseConfig(): { url: string; key: string } | null {\n // Try to get from environment variables\n const getEnvVar = (key: string): string | undefined => {\n if (typeof import.meta !== 'undefined' && (import.meta as any).env) {\n return (import.meta as any).env[key];\n }\n if (typeof process !== 'undefined' && process.env) {\n return process.env[key];\n }\n return undefined;\n };\n\n const supabaseUrl = getEnvVar('VITE_SUPABASE_URL') || \n getEnvVar('NEXT_PUBLIC_SUPABASE_URL') || \n null;\n \n const supabaseKey = getEnvVar('VITE_SUPABASE_PUBLISHABLE_KEY') || \n getEnvVar('NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY') || \n null;\n\n if (!supabaseUrl || !supabaseKey) {\n return null;\n }\n\n return { url: supabaseUrl, key: supabaseKey };\n}\n\n/**\n * Hook to get a secure Supabase client with automatic context injection\n * \n * Returns a secure client when organisation context is available,\n * otherwise returns null. The client automatically injects organisation\n * and event context into all database operations.\n * \n * Uses caching to prevent creating multiple Supabase client instances,\n * which causes the \"Multiple GoTrueClient instances\" warning.\n * \n * @param baseClient - Optional base Supabase client to use as fallback\n * @returns Secure Supabase client or null if context is not available\n * \n * @example\n * ```tsx\n * import { useSecureSupabase } from '@jmruthers/pace-core/rbac';\n * \n * function MyComponent() {\n * const supabase = useSecureSupabase();\n * \n * if (!supabase) {\n * return <div>Loading context...</div>;\n * }\n * \n * // Use supabase client - organisation context is automatically injected\n * const { data } = await supabase.from('users').select('*');\n * }\n * ```\n */\nexport function useSecureSupabase(\n baseClient?: SupabaseClient<Database> | null\n): SupabaseClient<Database> | null {\n const { user, supabase: authSupabase } = useUnifiedAuth();\n const { selectedOrganisation } = useOrganisations();\n const eventsContext = useEvents();\n const { selectedEvent } = eventsContext;\n const eventLoading = 'eventLoading' in eventsContext ? eventsContext.eventLoading : false;\n \n // Check super admin status for conditional filtering\n // Use verified status from useOrganisationSecurity which checks the database\n const { superAdminContext } = useOrganisationSecurity();\n const isSuperAdmin = superAdminContext.isSuperAdmin;\n\n // Resolve scope to get appId\n const { resolvedScope } = useResolvedScope({\n supabase: authSupabase || null,\n selectedOrganisationId: selectedOrganisation?.id || null,\n selectedEventId: selectedEvent?.event_id || null\n });\n\n // Track previous context to detect changes\n const prevContextRef = useRef<{\n organisationId: string | undefined;\n eventId: string | undefined;\n appId: string | undefined;\n }>({\n organisationId: undefined,\n eventId: undefined,\n appId: undefined\n });\n\n return useMemo(() => {\n // If event is loading, return base client or null to avoid recreating client unnecessarily\n if (eventLoading) {\n return baseClient || authSupabase || null;\n }\n \n // Use resolved scope to get organisationId (derived from event if needed)\n // For event-required apps, resolvedScope.organisationId is derived from event\n // For org-required apps, resolvedScope.organisationId comes from selectedOrganisation\n const organisationId = resolvedScope?.organisationId;\n const eventId = resolvedScope?.eventId || selectedEvent?.event_id;\n const appId = resolvedScope?.appId;\n \n // Allow super-admins to create a secure client even without organisationId\n // For non-super-admins, organisationId is required\n const canCreateSecureClient = user?.id && (isSuperAdmin || organisationId);\n \n if (canCreateSecureClient) {\n // Update previous context\n prevContextRef.current = { organisationId, eventId, appId };\n\n // Check cache first (must include isSuperAdmin in key for correct filtering)\n const cacheKey = getCacheKey(organisationId, eventId, appId, isSuperAdmin);\n const cachedClient = secureClientCache.get(cacheKey);\n\n if (cachedClient) {\n // Reuse cached client - prevents creating multiple instances\n return cachedClient.getClient();\n }\n\n // Get Supabase configuration\n const config = getSupabaseConfig();\n if (!config || !config.url || !config.key) {\n logger.warn('useSecureSupabase', 'Missing Supabase environment variables. Falling back to base client.', {\n note: 'Ensure VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are set in your environment.'\n });\n return baseClient || authSupabase || null;\n }\n\n try {\n // For super-admins, organisationId can be null\n const effectiveOrganisationId = isSuperAdmin ? (organisationId || null) : organisationId;\n \n const baseForSecureClient = baseClient || authSupabase || null;\n\n // IMPORTANT:\n // Reuse the existing authenticated client when possible to avoid:\n // - Multiple GoTrueClient instances warning\n // - Auth/session desync causing RLS SELECT to return empty after refresh\n const secureClient = baseForSecureClient\n ? fromSupabaseClient(\n baseForSecureClient as any,\n (effectiveOrganisationId as any) ?? null,\n eventId,\n appId as any,\n isSuperAdmin\n )\n : createSecureClient(\n config.url,\n config.key,\n effectiveOrganisationId as any, // organisationId is string | null, UUID is string alias\n eventId,\n appId as any, // appId is string | undefined, UUID is string alias\n isSuperAdmin // Pass super admin status for conditional filtering\n );\n\n // Cache the client for reuse\n secureClientCache.set(cacheKey, secureClient);\n\n // Clean up old cache entries to prevent memory leaks\n if (secureClientCache.size > MAX_CACHE_SIZE) {\n const firstKey = secureClientCache.keys().next().value;\n if (firstKey) {\n secureClientCache.delete(firstKey);\n }\n }\n\n // Return the underlying client for compatibility\n return secureClient.getClient();\n } catch (error) {\n logger.error('useSecureSupabase', 'Failed to create secure client', error);\n // Fallback to base client\n return baseClient || authSupabase || null;\n }\n }\n\n // Fallback to base client when context is not available\n return baseClient || authSupabase || null;\n }, [\n resolvedScope?.organisationId,\n resolvedScope?.eventId,\n resolvedScope?.appId,\n selectedEvent?.event_id,\n user?.id,\n eventLoading,\n isSuperAdmin,\n baseClient,\n authSupabase\n ]);\n}\n\n"],"mappings":"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","names":["contextValues","appName","error","ContextValidator","useState","useEffect","useMemo","logger","useState","error","useMemo","useEffect","useCallback","useEffect","useMemo","useState","useState","useCallback","error","useEffect","useMemo","useCallback","useEffect","useMemo","useState","useState","useCallback","useEffect","useMemo","useCallback","useEffect","useMemo","useRef","useState","useState","useEffect","checkSuperAdmin","useRef","useMemo","logger","useCallback","useCallback","useEffect","useMemo","useState","useState","useCallback","useEffect","useMemo","useCallback","useEffect","useMemo","useState","useState","useCallback","useEffect","useMemo","useCallback","useEffect","useMemo","useState","useState","useCallback","useEffect","useMemo","useCallback","useEffect","useMemo","useRef","useState","useState","useRef","logger","useEffect","useCallback","useMemo","useMemo","error","useMemo","useState","useCallback","useState","useCallback","useMemo","useRef","useRef","useMemo"]}