@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,33 +1,130 @@
1
- import {
2
- useAppConfig,
3
- useEvents,
4
- useOrganisationSecurity
5
- } from "./chunk-OEWDTMG7.js";
6
- import {
7
- useOrganisations,
8
- useUnifiedAuth
9
- } from "./chunk-AVMLPIM7.js";
10
- import {
11
- getAccessLevel,
12
- getPageScopeType,
13
- getPermissionMap,
14
- getRBACLogger,
15
- getRoleContext,
16
- isPermitted,
17
- isPermittedCached,
18
- resolveAppContext
19
- } from "./chunk-3LPHPB62.js";
20
- import {
21
- ContextValidator,
22
- OrganisationContextRequiredError
23
- } from "./chunk-36LVWXB2.js";
24
- import {
25
- getCurrentAppName
26
- } from "./chunk-M7MPQISP.js";
27
- import {
28
- createLogger,
29
- logger
30
- } from "./chunk-PWLANIRT.js";
1
+ import { useAppConfig, useOrganisationSecurity } from './chunk-3O3WHILE.js';
2
+ import { useEventService, useUnifiedAuth, useOrganisations } from './chunk-FTCRZOG2.js';
3
+ import { OrganisationContextRequiredError, getRBACLogger, resolveAppContext, getPageScopeType, ContextValidator, getPermissionMap, getRoleContext, getAccessLevel, isPermittedCached, isPermitted, isSuperAdmin } from './chunk-ZFYPMX46.js';
4
+ import { cn, getCurrentAppName } from './chunk-A55DK444.js';
5
+ import { createLogger, logger } from './chunk-TTRFSOKR.js';
6
+ import * as React from 'react';
7
+ import { useRef, useMemo, useState, useCallback, useEffect } from 'react';
8
+ import * as TooltipPrimitive from '@radix-ui/react-tooltip';
9
+ import { jsx, jsxs } from 'react/jsx-runtime';
10
+ import { Slot } from '@radix-ui/react-slot';
11
+ import { createClient } from '@supabase/supabase-js';
12
+
13
+ function useEvents() {
14
+ const eventService = useEventService();
15
+ const rawEvents = eventService.getEvents();
16
+ const selectedEvent = eventService.getSelectedEvent();
17
+ const isLoading = eventService.isLoading();
18
+ const error = eventService.getError();
19
+ const prevEventsRef = useRef([]);
20
+ const prevEventsIdsRef = useRef("");
21
+ const currentEventsIds = rawEvents.map((e) => e.event_id || e.id).join(",");
22
+ const eventsChanged = currentEventsIds !== prevEventsIdsRef.current;
23
+ if (eventsChanged) {
24
+ prevEventsRef.current = rawEvents;
25
+ prevEventsIdsRef.current = currentEventsIds;
26
+ }
27
+ const events = useMemo(() => {
28
+ return prevEventsRef.current;
29
+ }, [currentEventsIds]);
30
+ const setSelectedEventCallback = useMemo(
31
+ () => (event) => eventService.setSelectedEvent(event),
32
+ [eventService]
33
+ );
34
+ const refreshEventsCallback = useMemo(
35
+ () => () => eventService.refreshEvents(),
36
+ [eventService]
37
+ );
38
+ const clearEventSelectionCallback = useMemo(
39
+ () => () => eventService.clearEventSelection(),
40
+ [eventService]
41
+ );
42
+ return useMemo(() => ({
43
+ events,
44
+ selectedEvent,
45
+ isLoading,
46
+ error,
47
+ setSelectedEvent: setSelectedEventCallback,
48
+ refreshEvents: refreshEventsCallback,
49
+ clearEventSelection: clearEventSelectionCallback
50
+ }), [events, selectedEvent?.event_id, isLoading, error?.message, setSelectedEventCallback, refreshEventsCallback, clearEventSelectionCallback]);
51
+ }
52
+ var TooltipProvider = TooltipPrimitive.Provider;
53
+ var TooltipRoot = TooltipPrimitive.Root;
54
+ var TooltipTrigger = TooltipPrimitive.Trigger;
55
+ var TooltipContent = React.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
56
+ TooltipPrimitive.Content,
57
+ {
58
+ ref,
59
+ sideOffset,
60
+ className: cn(
61
+ "z-50 overflow-hidden rounded-md border bg-main-500 px-3 py-1.5 text-sm text-main-50 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
62
+ className
63
+ ),
64
+ ...props
65
+ }
66
+ ));
67
+ TooltipContent.displayName = TooltipPrimitive.Content.displayName;
68
+ var Tooltip = React.forwardRef(({ children, content, delayDuration = 200 }, ref) => /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
69
+ /* @__PURE__ */ jsx(TooltipTrigger, { ref, asChild: true, children: /* @__PURE__ */ jsx("span", { children }) }),
70
+ /* @__PURE__ */ jsx(TooltipContent, { children: content })
71
+ ] }) }));
72
+ Tooltip.displayName = "Tooltip";
73
+ function getButtonClasses(variant = "default", size = "default") {
74
+ const baseClasses = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50";
75
+ const variantClasses = {
76
+ default: "bg-main-600 text-main-50 shadow hover:bg-acc-400",
77
+ destructive: "bg-acc-600 text-acc-50 shadow-sm hover:bg-acc-400",
78
+ outline: "border border-main-300 bg-background shadow-sm hover:bg-acc-400",
79
+ secondary: "bg-sec-100 text-sec-900 shadow-sm hover:bg-acc-400",
80
+ ghost: "hover:bg-acc-400",
81
+ link: "text-main-700 underline-offset-4 hover:underline hover:drop-shadow-lg hover:drop-shadow-acc-400"
82
+ };
83
+ const sizeClasses = {
84
+ default: "h-9 px-4 py-2",
85
+ sm: "h-8 rounded-md px-3 text-xs",
86
+ lg: "h-10 rounded-md px-8",
87
+ icon: "size-8"
88
+ };
89
+ return `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`;
90
+ }
91
+ var Button = React.forwardRef(
92
+ ({ className, variant, size, asChild = false, type = "button", disabled, ...props }, ref) => {
93
+ const Comp = asChild ? Slot : "button";
94
+ return /* @__PURE__ */ jsx(
95
+ Comp,
96
+ {
97
+ className: cn(getButtonClasses(variant, size), className),
98
+ ref,
99
+ type: !asChild ? type : void 0,
100
+ disabled,
101
+ "aria-disabled": disabled ? "true" : void 0,
102
+ ...props
103
+ }
104
+ );
105
+ }
106
+ );
107
+ Button.displayName = "Button";
108
+ var IconButton = React.forwardRef(
109
+ ({ icon, className, size = "icon", "aria-label": ariaLabel, tooltip, ...props }, ref) => {
110
+ const button = /* @__PURE__ */ jsx(
111
+ Button,
112
+ {
113
+ ref,
114
+ size,
115
+ className: cn("shrink-0", className),
116
+ "aria-label": ariaLabel,
117
+ ...props,
118
+ children: icon
119
+ }
120
+ );
121
+ if (tooltip) {
122
+ return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, children: button });
123
+ }
124
+ return button;
125
+ }
126
+ );
127
+ IconButton.displayName = "IconButton";
31
128
 
32
129
  // src/rbac/utils/clientSecurity.ts
33
130
  var SECURE_CLIENT_SYMBOL = Symbol("pace-core-secure-client");
@@ -61,11 +158,8 @@ See: https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/rbac/ge
61
158
  function markClientAsSecure(client) {
62
159
  client[SECURE_CLIENT_SYMBOL] = true;
63
160
  }
64
-
65
- // src/rbac/secureClient.ts
66
- import { createClient } from "@supabase/supabase-js";
67
161
  var _SecureSupabaseClient = class _SecureSupabaseClient {
68
- constructor(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin = false, existingClient) {
162
+ constructor(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2 = false, existingClient) {
69
163
  this.edgeFunctionClient = null;
70
164
  this.usesExistingClient = false;
71
165
  this.supabaseUrl = supabaseUrl;
@@ -73,7 +167,7 @@ var _SecureSupabaseClient = class _SecureSupabaseClient {
73
167
  this.organisationId = organisationId;
74
168
  this.eventId = eventId;
75
169
  this.appId = appId;
76
- this.isSuperAdmin = isSuperAdmin;
170
+ this.isSuperAdmin = isSuperAdmin2;
77
171
  if (existingClient) {
78
172
  this.supabase = existingClient;
79
173
  this.usesExistingClient = true;
@@ -422,200 +516,12 @@ _SecureSupabaseClient.GLOBAL_RPC_ALLOWLIST = /* @__PURE__ */ new Set([
422
516
  "data_rbac_apps_list"
423
517
  ]);
424
518
  var SecureSupabaseClient = _SecureSupabaseClient;
425
- function createSecureClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin = false) {
426
- return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin);
519
+ function createSecureClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2 = false) {
520
+ return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2);
427
521
  }
428
- function fromSupabaseClient(client, organisationId, eventId, appId, isSuperAdmin = false) {
429
- return new SecureSupabaseClient("", "", organisationId, eventId, appId, isSuperAdmin, client);
522
+ function fromSupabaseClient(client, organisationId, eventId, appId, isSuperAdmin2 = false) {
523
+ return new SecureSupabaseClient("", "", organisationId, eventId, appId, isSuperAdmin2, client);
430
524
  }
431
-
432
- // src/rbac/hooks/useResolvedScope.ts
433
- import { useEffect, useState, useRef, useMemo } from "react";
434
- var log = createLogger("useResolvedScope");
435
- var appIdCache = /* @__PURE__ */ new Map();
436
- var CACHE_TTL = 5 * 60 * 1e3;
437
- function useResolvedScope({
438
- supabase,
439
- selectedOrganisationId,
440
- selectedEventId
441
- }) {
442
- const [resolvedScope, setResolvedScope] = useState(null);
443
- const [isLoading, setIsLoading] = useState(true);
444
- const [error, setError] = useState(null);
445
- const stableScopeRef = useRef({
446
- organisationId: "",
447
- appId: "",
448
- eventId: void 0
449
- });
450
- useEffect(() => {
451
- if (resolvedScope) {
452
- const newScope = {
453
- organisationId: resolvedScope.organisationId || "",
454
- appId: resolvedScope.appId || "",
455
- eventId: resolvedScope.eventId
456
- };
457
- if (stableScopeRef.current.organisationId !== newScope.organisationId || stableScopeRef.current.eventId !== newScope.eventId || stableScopeRef.current.appId !== newScope.appId) {
458
- stableScopeRef.current = {
459
- organisationId: newScope.organisationId,
460
- appId: newScope.appId,
461
- eventId: newScope.eventId
462
- };
463
- }
464
- } else {
465
- stableScopeRef.current = { organisationId: "", appId: "", eventId: void 0 };
466
- }
467
- }, [resolvedScope]);
468
- const appName = getCurrentAppName();
469
- const stableScope = stableScopeRef.current;
470
- useEffect(() => {
471
- let cancelled = false;
472
- const resolveScope = async () => {
473
- if (!supabase && !selectedOrganisationId && !selectedEventId) {
474
- if (!cancelled) {
475
- setResolvedScope(null);
476
- setIsLoading(false);
477
- setError(null);
478
- }
479
- return;
480
- }
481
- setIsLoading(true);
482
- setError(null);
483
- try {
484
- const appName2 = getCurrentAppName();
485
- let appId = void 0;
486
- if (supabase && appName2) {
487
- try {
488
- const { data: session } = await supabase.auth.getSession();
489
- if (!session?.session) {
490
- log.debug(`Skipping app resolution for "${appName2}" - user not authenticated`);
491
- } else {
492
- const cached = appIdCache.get(appName2);
493
- const now = Date.now();
494
- if (cached && now - cached.timestamp < CACHE_TTL) {
495
- appId = cached.appId;
496
- } else {
497
- const { data: app, error: error2 } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).eq("is_active", true).single();
498
- if (error2) {
499
- if (error2.code === "406" || error2.code === "PGRST116" || error2.message?.includes("406")) {
500
- log.debug(`App resolution blocked by RLS for "${appName2}" - user may not be authenticated`);
501
- appId = void 0;
502
- } else {
503
- const { data: inactiveApp } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).single();
504
- if (inactiveApp) {
505
- log.error(`App "${appName2}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
506
- appId = void 0;
507
- } else {
508
- log.error(`App "${appName2}" not found in rbac_apps table`, { error: error2 });
509
- appId = void 0;
510
- }
511
- }
512
- } else if (app) {
513
- appId = app.id;
514
- appIdCache.set(appName2, { appId, timestamp: now });
515
- }
516
- }
517
- }
518
- } catch (error2) {
519
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
520
- if (!errorMessage.includes("406") && !errorMessage.includes("PGRST116")) {
521
- log.error("Unexpected error resolving app ID:", error2);
522
- } else {
523
- log.debug("App resolution skipped - authentication required");
524
- }
525
- }
526
- }
527
- const initialScope = {
528
- organisationId: selectedOrganisationId || void 0,
529
- eventId: selectedEventId || void 0,
530
- appId
531
- };
532
- if (appName2 === "PORTAL" || appName2 === "ADMIN") {
533
- if (!cancelled) {
534
- const optionalContextScope = {
535
- organisationId: void 0,
536
- eventId: void 0,
537
- appId: appId || void 0
538
- };
539
- setResolvedScope(optionalContextScope);
540
- setError(null);
541
- setIsLoading(false);
542
- }
543
- return;
544
- }
545
- const { ContextValidator: ContextValidator2 } = await import("./contextValidator-OOPCLPZW.js");
546
- const validation = await ContextValidator2.resolveScopeForPage(
547
- initialScope,
548
- "organisation",
549
- // Default to organisation scope when no page context
550
- appName2 || void 0,
551
- supabase
552
- );
553
- if (!validation.isValid) {
554
- if (selectedEventId) {
555
- if (!cancelled) {
556
- const eventScope = {
557
- organisationId: void 0,
558
- // Will be derived from event during permission check
559
- eventId: selectedEventId,
560
- appId: appId || void 0
561
- };
562
- setResolvedScope(eventScope);
563
- setError(null);
564
- setIsLoading(false);
565
- }
566
- return;
567
- }
568
- if (!cancelled) {
569
- setResolvedScope(null);
570
- setError(validation.error || new Error("Context validation failed"));
571
- setIsLoading(false);
572
- }
573
- return;
574
- }
575
- if (!cancelled) {
576
- setResolvedScope(validation.resolvedScope);
577
- setError(null);
578
- setIsLoading(false);
579
- }
580
- } catch (err) {
581
- if (!cancelled) {
582
- setError(err);
583
- setIsLoading(false);
584
- }
585
- }
586
- };
587
- resolveScope();
588
- return () => {
589
- cancelled = true;
590
- };
591
- }, [selectedOrganisationId, selectedEventId, supabase]);
592
- const allowsOptionalContexts = appName === "PORTAL" || appName === "ADMIN";
593
- const hasValidScope = allowsOptionalContexts ? true : stableScope.appId || stableScope.organisationId;
594
- const finalScope = useMemo(() => {
595
- if (!hasValidScope) {
596
- return allowsOptionalContexts ? {} : null;
597
- }
598
- const scope = {};
599
- if (stableScope.organisationId) {
600
- scope.organisationId = stableScope.organisationId;
601
- }
602
- if (stableScope.eventId) {
603
- scope.eventId = stableScope.eventId;
604
- }
605
- if (stableScope.appId) {
606
- scope.appId = stableScope.appId;
607
- }
608
- return scope;
609
- }, [hasValidScope, allowsOptionalContexts, stableScope.organisationId, stableScope.eventId, stableScope.appId]);
610
- return {
611
- resolvedScope: finalScope,
612
- isLoading,
613
- error
614
- };
615
- }
616
-
617
- // src/rbac/hooks/useRBAC.ts
618
- import { useState as useState2, useEffect as useEffect2, useCallback, useMemo as useMemo2 } from "react";
619
525
  function mapAccessLevelToEventRole(level) {
620
526
  switch (level) {
621
527
  case "viewer":
@@ -645,13 +551,13 @@ function useRBAC(pageId) {
645
551
  selectedEvent,
646
552
  eventLoading
647
553
  } = useUnifiedAuth();
648
- const [globalRole, setGlobalRole] = useState2(null);
649
- const [organisationRole, setOrganisationRole] = useState2(null);
650
- const [eventAppRole, setEventAppRole] = useState2(null);
651
- const [permissionMap, setPermissionMap] = useState2({});
652
- const [currentScope, setCurrentScope] = useState2(null);
653
- const [isLoading, setIsLoading] = useState2(false);
654
- const [error, setError] = useState2(null);
554
+ const [globalRole, setGlobalRole] = useState(null);
555
+ const [organisationRole, setOrganisationRole] = useState(null);
556
+ const [eventAppRole, setEventAppRole] = useState(null);
557
+ const [permissionMap, setPermissionMap] = useState({});
558
+ const [currentScope, setCurrentScope] = useState(null);
559
+ const [isLoading, setIsLoading] = useState(false);
560
+ const [error, setError] = useState(null);
655
561
  const resetState = useCallback(() => {
656
562
  setGlobalRole(null);
657
563
  setOrganisationRole(null);
@@ -737,9 +643,9 @@ function useRBAC(pageId) {
737
643
  const resolvedScope = validation.resolvedScope;
738
644
  setCurrentScope(resolvedScope);
739
645
  const [map, roleContext, accessLevel] = await Promise.all([
740
- getPermissionMap({ userId: user.id, scope: resolvedScope }),
741
- getRoleContext({ userId: user.id, scope: resolvedScope }),
742
- getAccessLevel({ userId: user.id, scope: resolvedScope })
646
+ getPermissionMap({ userId: user.id, scope: resolvedScope }, appName),
647
+ getRoleContext({ userId: user.id, scope: resolvedScope }, appName),
648
+ getAccessLevel({ userId: user.id, scope: resolvedScope }, appName)
743
649
  ]);
744
650
  setPermissionMap(map);
745
651
  setGlobalRole(roleContext.globalRole);
@@ -777,12 +683,12 @@ function useRBAC(pageId) {
777
683
  },
778
684
  [globalRole, organisationRole, permissionMap]
779
685
  );
780
- const isSuperAdmin = useMemo2(() => globalRole === "super_admin" || permissionMap["*"] === true, [globalRole, permissionMap]);
781
- const isOrgAdmin = useMemo2(() => organisationRole === "org_admin" || isSuperAdmin, [organisationRole, isSuperAdmin]);
782
- const isEventAdmin = useMemo2(() => eventAppRole === "event_admin" || isSuperAdmin, [eventAppRole, isSuperAdmin]);
783
- const canManageOrganisation = useMemo2(() => isSuperAdmin || organisationRole === "org_admin", [isSuperAdmin, organisationRole]);
784
- const canManageEvent = useMemo2(() => isSuperAdmin || eventAppRole === "event_admin", [isSuperAdmin, eventAppRole]);
785
- useEffect2(() => {
686
+ const isSuperAdmin2 = useMemo(() => globalRole === "super_admin" || permissionMap["*"] === true, [globalRole, permissionMap]);
687
+ const isOrgAdmin = useMemo(() => organisationRole === "org_admin" || isSuperAdmin2, [organisationRole, isSuperAdmin2]);
688
+ const isEventAdmin = useMemo(() => eventAppRole === "event_admin" || isSuperAdmin2, [eventAppRole, isSuperAdmin2]);
689
+ const canManageOrganisation = useMemo(() => isSuperAdmin2 || organisationRole === "org_admin", [isSuperAdmin2, organisationRole]);
690
+ const canManageEvent = useMemo(() => isSuperAdmin2 || eventAppRole === "event_admin", [isSuperAdmin2, eventAppRole]);
691
+ useEffect(() => {
786
692
  loadRBACContext();
787
693
  }, [loadRBACContext, appName, eventLoading, selectedEvent?.event_id, user, session, selectedOrganisation?.id, orgContextReady, orgLoading]);
788
694
  return {
@@ -791,7 +697,7 @@ function useRBAC(pageId) {
791
697
  organisationRole,
792
698
  eventAppRole,
793
699
  hasGlobalPermission,
794
- isSuperAdmin,
700
+ isSuperAdmin: isSuperAdmin2,
795
701
  isOrgAdmin,
796
702
  isEventAdmin,
797
703
  canManageOrganisation,
@@ -800,20 +706,131 @@ function useRBAC(pageId) {
800
706
  error
801
707
  };
802
708
  }
803
-
804
- // src/rbac/hooks/permissions/useAccessLevel.ts
805
- import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo3, useState as useState3 } from "react";
709
+ var log = createLogger("useResolvedScope");
710
+ var appIdCache = /* @__PURE__ */ new Map();
711
+ var CACHE_TTL = 5 * 60 * 1e3;
712
+ function useResolvedScope({
713
+ supabase,
714
+ selectedOrganisationId,
715
+ selectedEventId,
716
+ selectedEventOrganisationId
717
+ }) {
718
+ const immediateOrganisationId = selectedEventOrganisationId || selectedOrganisationId || void 0;
719
+ const immediateEventId = selectedEventId || void 0;
720
+ const [appId, setAppId] = useState(void 0);
721
+ const [isResolvingAppId, setIsResolvingAppId] = useState(false);
722
+ const [error, setError] = useState(null);
723
+ const appName = getCurrentAppName();
724
+ useEffect(() => {
725
+ let cancelled = false;
726
+ const resolveAppId = async () => {
727
+ if (!supabase && !selectedOrganisationId && !selectedEventId) {
728
+ if (!cancelled) {
729
+ setAppId(void 0);
730
+ setIsResolvingAppId(false);
731
+ setError(null);
732
+ }
733
+ return;
734
+ }
735
+ setIsResolvingAppId(true);
736
+ setError(null);
737
+ try {
738
+ const appName2 = getCurrentAppName();
739
+ let resolvedAppId = void 0;
740
+ if (supabase && appName2) {
741
+ try {
742
+ const { data: session } = await supabase.auth.getSession();
743
+ if (!session?.session) {
744
+ log.debug(`Skipping app resolution for "${appName2}" - user not authenticated`);
745
+ } else {
746
+ const cached = appIdCache.get(appName2);
747
+ const now = Date.now();
748
+ if (cached && now - cached.timestamp < CACHE_TTL) {
749
+ resolvedAppId = cached.appId;
750
+ } else {
751
+ const { data: app, error: error2 } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).eq("is_active", true).single();
752
+ if (error2) {
753
+ if (error2.code === "406" || error2.code === "PGRST116" || error2.message?.includes("406")) {
754
+ log.debug(`App resolution blocked by RLS for "${appName2}" - user may not be authenticated`);
755
+ resolvedAppId = void 0;
756
+ } else {
757
+ const { data: inactiveApp } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).single();
758
+ if (inactiveApp) {
759
+ log.error(`App "${appName2}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
760
+ resolvedAppId = void 0;
761
+ } else {
762
+ log.error(`App "${appName2}" not found in rbac_apps table`, { error: error2 });
763
+ resolvedAppId = void 0;
764
+ }
765
+ }
766
+ } else if (app) {
767
+ resolvedAppId = app.id;
768
+ appIdCache.set(appName2, { appId: resolvedAppId, timestamp: now });
769
+ }
770
+ }
771
+ }
772
+ } catch (error2) {
773
+ const errorMessage = error2 instanceof Error ? error2.message : String(error2);
774
+ if (!errorMessage.includes("406") && !errorMessage.includes("PGRST116")) {
775
+ log.error("Unexpected error resolving app ID:", error2);
776
+ } else {
777
+ log.debug("App resolution skipped - authentication required");
778
+ }
779
+ }
780
+ }
781
+ if (!cancelled) {
782
+ setAppId(resolvedAppId);
783
+ setIsResolvingAppId(false);
784
+ setError(null);
785
+ }
786
+ } catch (err) {
787
+ if (!cancelled) {
788
+ setError(err);
789
+ setIsResolvingAppId(false);
790
+ }
791
+ }
792
+ };
793
+ resolveAppId();
794
+ return () => {
795
+ cancelled = true;
796
+ };
797
+ }, [supabase, selectedOrganisationId, selectedEventId]);
798
+ const immediateScope = useMemo(() => {
799
+ if (appName === "PORTAL" || appName === "ADMIN") {
800
+ return {
801
+ organisationId: void 0,
802
+ eventId: void 0,
803
+ appId: appId || void 0
804
+ };
805
+ }
806
+ const scope = {};
807
+ if (immediateOrganisationId) {
808
+ scope.organisationId = immediateOrganisationId;
809
+ }
810
+ if (immediateEventId) {
811
+ scope.eventId = immediateEventId;
812
+ }
813
+ if (appId) {
814
+ scope.appId = appId;
815
+ }
816
+ if (!scope.organisationId && !scope.appId) {
817
+ return null;
818
+ }
819
+ return scope;
820
+ }, [immediateOrganisationId, immediateEventId, appId, appName]);
821
+ return {
822
+ resolvedScope: immediateScope,
823
+ isLoading: isResolvingAppId,
824
+ // Only true while appId resolves
825
+ error
826
+ };
827
+ }
806
828
  function useAccessLevel(userId, scope) {
807
- const [accessLevel, setAccessLevel] = useState3("viewer");
808
- const [isLoading, setIsLoading] = useState3(true);
809
- const [error, setError] = useState3(null);
810
- let appName;
811
- try {
812
- const { appName: contextAppName } = useAppConfig();
813
- appName = contextAppName;
814
- } catch {
815
- }
816
- const fetchAccessLevel = useCallback2(async () => {
829
+ const [accessLevel, setAccessLevel] = useState("viewer");
830
+ const [isLoading, setIsLoading] = useState(true);
831
+ const [error, setError] = useState(null);
832
+ const { appName } = useAppConfig();
833
+ const fetchAccessLevel = useCallback(async () => {
817
834
  if (!userId) {
818
835
  setAccessLevel("viewer");
819
836
  setIsLoading(false);
@@ -822,7 +839,7 @@ function useAccessLevel(userId, scope) {
822
839
  try {
823
840
  setIsLoading(true);
824
841
  setError(null);
825
- const { isSuperAdmin: checkSuperAdmin } = await import("./api-6LVZTHDS.js");
842
+ const { isSuperAdmin: checkSuperAdmin } = await import('./api-Y4MQWOFW.js');
826
843
  const isSuperAdminUser = await checkSuperAdmin(userId);
827
844
  if (isSuperAdminUser) {
828
845
  setAccessLevel("super");
@@ -846,10 +863,10 @@ function useAccessLevel(userId, scope) {
846
863
  setIsLoading(false);
847
864
  }
848
865
  }, [userId, scope.organisationId, scope.eventId, scope.appId, appName]);
849
- useEffect3(() => {
866
+ useEffect(() => {
850
867
  fetchAccessLevel();
851
868
  }, [fetchAccessLevel]);
852
- return useMemo3(() => ({
869
+ return useMemo(() => ({
853
870
  accessLevel,
854
871
  isLoading,
855
872
  error,
@@ -857,47 +874,6 @@ function useAccessLevel(userId, scope) {
857
874
  }), [accessLevel, isLoading, error, fetchAccessLevel]);
858
875
  }
859
876
 
860
- // src/rbac/hooks/permissions/useCachedPermissions.ts
861
- import { useCallback as useCallback3, useEffect as useEffect4, useMemo as useMemo4, useState as useState4 } from "react";
862
- function useCachedPermissions(userId, scope) {
863
- const [permissions, setPermissions] = useState4({});
864
- const [isLoading, setIsLoading] = useState4(true);
865
- const [error, setError] = useState4(null);
866
- const fetchCachedPermissions = useCallback3(async () => {
867
- if (!userId) {
868
- setPermissions({});
869
- setIsLoading(false);
870
- return;
871
- }
872
- try {
873
- setIsLoading(true);
874
- setError(null);
875
- const permissionMap = await getPermissionMap({ userId, scope });
876
- setPermissions(permissionMap);
877
- } catch (err) {
878
- setError(err instanceof Error ? err : new Error("Failed to fetch cached permissions"));
879
- } finally {
880
- setIsLoading(false);
881
- }
882
- }, [userId, scope.organisationId, scope.eventId, scope.appId]);
883
- const invalidateCache = useCallback3(() => {
884
- fetchCachedPermissions();
885
- }, [fetchCachedPermissions]);
886
- useEffect4(() => {
887
- fetchCachedPermissions();
888
- }, [fetchCachedPermissions]);
889
- return useMemo4(() => ({
890
- permissions,
891
- isLoading,
892
- error,
893
- invalidateCache,
894
- refetch: fetchCachedPermissions
895
- }), [permissions, isLoading, error, invalidateCache, fetchCachedPermissions]);
896
- }
897
-
898
- // src/rbac/hooks/permissions/useCan.ts
899
- import { useCallback as useCallback4, useEffect as useEffect5, useMemo as useMemo5, useRef as useRef2, useState as useState5 } from "react";
900
-
901
877
  // src/rbac/utils/deep-equal.ts
902
878
  function scopeEqual(a, b) {
903
879
  if (a === b) {
@@ -911,27 +887,27 @@ function scopeEqual(a, b) {
911
887
 
912
888
  // src/rbac/hooks/permissions/useCan.ts
913
889
  function useCan(userId, scope, permission, pageId, useCache = true, precomputedSuperAdmin = null, appName) {
914
- const [isSuperAdmin, setIsSuperAdmin] = useState5(precomputedSuperAdmin ?? null);
890
+ const [isSuperAdmin2, setIsSuperAdmin] = useState(precomputedSuperAdmin ?? null);
915
891
  const initialCan = precomputedSuperAdmin === true ? true : false;
916
892
  const initialIsLoading = precomputedSuperAdmin === true ? false : true;
917
- const [can, setCan] = useState5(initialCan);
918
- const [isLoading, setIsLoading] = useState5(initialIsLoading);
919
- const [error, setError] = useState5(null);
893
+ const [can, setCan] = useState(initialCan);
894
+ const [isLoading, setIsLoading] = useState(initialIsLoading);
895
+ const [error, setError] = useState(null);
920
896
  const isValidScope = scope && typeof scope === "object";
921
897
  const organisationId = isValidScope ? scope.organisationId : void 0;
922
898
  const eventId = isValidScope ? scope.eventId : void 0;
923
899
  const appId = isValidScope ? scope.appId : void 0;
924
- useEffect5(() => {
925
- if (precomputedSuperAdmin === true && isSuperAdmin !== true) {
900
+ useEffect(() => {
901
+ if (precomputedSuperAdmin === true && isSuperAdmin2 !== true) {
926
902
  setIsSuperAdmin(true);
927
903
  setCan(true);
928
904
  setIsLoading(false);
929
905
  setError(null);
930
- } else if (precomputedSuperAdmin === false && isSuperAdmin !== false) {
906
+ } else if (precomputedSuperAdmin === false && isSuperAdmin2 !== false) {
931
907
  setIsSuperAdmin(false);
932
908
  }
933
- }, [precomputedSuperAdmin, isSuperAdmin]);
934
- useEffect5(() => {
909
+ }, [precomputedSuperAdmin, isSuperAdmin2]);
910
+ useEffect(() => {
935
911
  if (precomputedSuperAdmin === null) {
936
912
  if (!userId) {
937
913
  setIsSuperAdmin(false);
@@ -941,7 +917,7 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
941
917
  const checkSuperAdmin = async () => {
942
918
  const startTime = Date.now();
943
919
  try {
944
- const { isSuperAdmin: checkSuperAdmin2 } = await import("./api-6LVZTHDS.js");
920
+ const { isSuperAdmin: checkSuperAdmin2 } = await import('./api-Y4MQWOFW.js');
945
921
  const timeoutWarning = setTimeout(() => {
946
922
  if (!cancelled) {
947
923
  console.warn("[useCan] Super admin check taking longer than 5 seconds", {
@@ -985,10 +961,10 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
985
961
  };
986
962
  }
987
963
  }, [userId, precomputedSuperAdmin]);
988
- useEffect5(() => {
964
+ useEffect(() => {
989
965
  const isPagePermission = permission.includes(":page.") || !!pageId;
990
966
  const requiresOrgId = !isPagePermission;
991
- if (isSuperAdmin === true) {
967
+ if (isSuperAdmin2 === true) {
992
968
  return;
993
969
  }
994
970
  if (requiresOrgId && (!isValidScope || !organisationId || organisationId === null || typeof organisationId === "string" && organisationId.trim() === "")) {
@@ -1002,14 +978,14 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
1002
978
  if (error?.message === "Organisation context is required for permission checks") {
1003
979
  setError(null);
1004
980
  }
1005
- }, [isValidScope, organisationId, error, permission, pageId, isSuperAdmin]);
1006
- const lastUserIdRef = useRef2(null);
1007
- const lastScopeRef = useRef2(null);
1008
- const lastPermissionRef = useRef2(null);
1009
- const lastPageIdRef = useRef2(null);
1010
- const lastUseCacheRef = useRef2(null);
1011
- const lastIsSuperAdminRef = useRef2(null);
1012
- const stableScope = useMemo5(() => {
981
+ }, [isValidScope, organisationId, error, permission, pageId, isSuperAdmin2]);
982
+ const lastUserIdRef = useRef(null);
983
+ useRef(null);
984
+ const lastPermissionRef = useRef(null);
985
+ const lastPageIdRef = useRef(null);
986
+ const lastUseCacheRef = useRef(null);
987
+ const lastIsSuperAdminRef = useRef(null);
988
+ const stableScope = useMemo(() => {
1013
989
  if (!isValidScope) {
1014
990
  return null;
1015
991
  }
@@ -1019,12 +995,12 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
1019
995
  appId
1020
996
  };
1021
997
  }, [isValidScope, organisationId, eventId, appId]);
1022
- const prevScopeRef = useRef2(null);
1023
- useEffect5(() => {
998
+ const prevScopeRef = useRef(null);
999
+ useEffect(() => {
1024
1000
  const scopeChanged = !scopeEqual(prevScopeRef.current, stableScope);
1025
- const isSuperAdminChanged = lastIsSuperAdminRef.current !== isSuperAdmin;
1001
+ const isSuperAdminChanged = lastIsSuperAdminRef.current !== isSuperAdmin2;
1026
1002
  if (lastUserIdRef.current !== userId || scopeChanged || lastPermissionRef.current !== permission || lastPageIdRef.current !== pageId || lastUseCacheRef.current !== useCache || isSuperAdminChanged) {
1027
- lastIsSuperAdminRef.current = isSuperAdmin;
1003
+ lastIsSuperAdminRef.current = isSuperAdmin2;
1028
1004
  lastUserIdRef.current = userId;
1029
1005
  prevScopeRef.current = stableScope;
1030
1006
  lastPermissionRef.current = permission;
@@ -1036,13 +1012,13 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
1036
1012
  setIsLoading(false);
1037
1013
  return;
1038
1014
  }
1039
- if (isSuperAdmin === true) {
1015
+ if (isSuperAdmin2 === true) {
1040
1016
  setCan(true);
1041
1017
  setIsLoading(false);
1042
1018
  setError(null);
1043
1019
  return;
1044
1020
  }
1045
- if (isSuperAdmin === null) {
1021
+ if (isSuperAdmin2 === null) {
1046
1022
  setIsLoading(true);
1047
1023
  setCan(false);
1048
1024
  setError(null);
@@ -1078,7 +1054,7 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
1078
1054
  ...eventId ? { eventId } : {},
1079
1055
  ...appId ? { appId } : {}
1080
1056
  };
1081
- const result = useCache ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName) : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, isSuperAdmin === false ? false : null);
1057
+ const result = useCache ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName) : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, isSuperAdmin2 === false ? false : null);
1082
1058
  setCan(result);
1083
1059
  } catch (err) {
1084
1060
  const logger2 = getRBACLogger();
@@ -1092,8 +1068,8 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
1092
1068
  };
1093
1069
  checkPermission();
1094
1070
  }
1095
- }, [userId, stableScope, permission, pageId, useCache, appName, isSuperAdmin]);
1096
- const refetch = useCallback4(async () => {
1071
+ }, [userId, stableScope, permission, pageId, useCache, appName, isSuperAdmin2]);
1072
+ const refetch = useCallback(async () => {
1097
1073
  if (!userId) {
1098
1074
  setCan(false);
1099
1075
  setIsLoading(false);
@@ -1130,105 +1106,18 @@ function useCan(userId, scope, permission, pageId, useCache = true, precomputedS
1130
1106
  setIsLoading(false);
1131
1107
  }
1132
1108
  }, [userId, isValidScope, organisationId, eventId, appId, permission, pageId, useCache, appName]);
1133
- return useMemo5(() => ({
1109
+ return useMemo(() => ({
1134
1110
  can,
1135
1111
  isLoading,
1136
1112
  error,
1137
1113
  refetch
1138
1114
  }), [can, isLoading, error, refetch]);
1139
1115
  }
1140
-
1141
- // src/rbac/hooks/permissions/useHasAllPermissions.ts
1142
- import { useCallback as useCallback5, useEffect as useEffect6, useMemo as useMemo6, useState as useState6 } from "react";
1143
- function useHasAllPermissions(userId, scope, permissions, useCache = true) {
1144
- const [hasAll, setHasAll] = useState6(false);
1145
- const [isLoading, setIsLoading] = useState6(true);
1146
- const [error, setError] = useState6(null);
1147
- const checkAllPermissions = useCallback5(async () => {
1148
- if (!userId || permissions.length === 0) {
1149
- setHasAll(false);
1150
- setIsLoading(false);
1151
- return;
1152
- }
1153
- try {
1154
- setIsLoading(true);
1155
- setError(null);
1156
- let hasAllPermissions = true;
1157
- for (const permission of permissions) {
1158
- const result = useCache ? await isPermittedCached({ userId, scope, permission }) : await isPermitted({ userId, scope, permission });
1159
- if (!result) {
1160
- hasAllPermissions = false;
1161
- break;
1162
- }
1163
- }
1164
- setHasAll(hasAllPermissions);
1165
- } catch (err) {
1166
- setError(err instanceof Error ? err : new Error("Failed to check permissions"));
1167
- setHasAll(false);
1168
- } finally {
1169
- setIsLoading(false);
1170
- }
1171
- }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
1172
- useEffect6(() => {
1173
- checkAllPermissions();
1174
- }, [checkAllPermissions]);
1175
- return useMemo6(() => ({
1176
- hasAll,
1177
- isLoading,
1178
- error,
1179
- refetch: checkAllPermissions
1180
- }), [hasAll, isLoading, error, checkAllPermissions]);
1181
- }
1182
-
1183
- // src/rbac/hooks/permissions/useHasAnyPermission.ts
1184
- import { useCallback as useCallback6, useEffect as useEffect7, useMemo as useMemo7, useState as useState7 } from "react";
1185
- function useHasAnyPermission(userId, scope, permissions, useCache = true) {
1186
- const [hasAny, setHasAny] = useState7(false);
1187
- const [isLoading, setIsLoading] = useState7(true);
1188
- const [error, setError] = useState7(null);
1189
- const checkAnyPermission = useCallback6(async () => {
1190
- if (!userId || permissions.length === 0) {
1191
- setHasAny(false);
1192
- setIsLoading(false);
1193
- return;
1194
- }
1195
- try {
1196
- setIsLoading(true);
1197
- setError(null);
1198
- let hasAnyPermission = false;
1199
- for (const permission of permissions) {
1200
- const result = useCache ? await isPermittedCached({ userId, scope, permission }) : await isPermitted({ userId, scope, permission });
1201
- if (result) {
1202
- hasAnyPermission = true;
1203
- break;
1204
- }
1205
- }
1206
- setHasAny(hasAnyPermission);
1207
- } catch (err) {
1208
- setError(err instanceof Error ? err : new Error("Failed to check permissions"));
1209
- setHasAny(false);
1210
- } finally {
1211
- setIsLoading(false);
1212
- }
1213
- }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
1214
- useEffect7(() => {
1215
- checkAnyPermission();
1216
- }, [checkAnyPermission]);
1217
- return useMemo7(() => ({
1218
- hasAny,
1219
- isLoading,
1220
- error,
1221
- refetch: checkAnyPermission
1222
- }), [hasAny, isLoading, error, checkAnyPermission]);
1223
- }
1224
-
1225
- // src/rbac/hooks/permissions/useMultiplePermissions.ts
1226
- import { useCallback as useCallback7, useEffect as useEffect8, useMemo as useMemo8, useState as useState8 } from "react";
1227
1116
  function useMultiplePermissions(userId, scope, permissions, useCache = true) {
1228
- const [results, setResults] = useState8({});
1229
- const [isLoading, setIsLoading] = useState8(true);
1230
- const [error, setError] = useState8(null);
1231
- const checkPermissions = useCallback7(async () => {
1117
+ const [results, setResults] = useState({});
1118
+ const [isLoading, setIsLoading] = useState(true);
1119
+ const [error, setError] = useState(null);
1120
+ const checkPermissions = useCallback(async () => {
1232
1121
  if (!userId || permissions.length === 0) {
1233
1122
  setResults({});
1234
1123
  setIsLoading(false);
@@ -1250,29 +1139,26 @@ function useMultiplePermissions(userId, scope, permissions, useCache = true) {
1250
1139
  setIsLoading(false);
1251
1140
  }
1252
1141
  }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
1253
- useEffect8(() => {
1142
+ useEffect(() => {
1254
1143
  checkPermissions();
1255
1144
  }, [checkPermissions]);
1256
- return useMemo8(() => ({
1145
+ return useMemo(() => ({
1257
1146
  results,
1258
1147
  isLoading,
1259
1148
  error,
1260
1149
  refetch: checkPermissions
1261
1150
  }), [results, isLoading, error, checkPermissions]);
1262
1151
  }
1263
-
1264
- // src/rbac/hooks/permissions/usePermissions.ts
1265
- import { useCallback as useCallback8, useEffect as useEffect9, useMemo as useMemo9, useRef as useRef3, useState as useState9 } from "react";
1266
1152
  function usePermissions(userId, organisationId, eventId, appId) {
1267
- const [permissions, setPermissions] = useState9({});
1268
- const [isLoading, setIsLoading] = useState9(true);
1269
- const [error, setError] = useState9(null);
1270
- const [fetchTrigger, setFetchTrigger] = useState9(0);
1271
- const isFetchingRef = useRef3(false);
1153
+ const [permissions, setPermissions] = useState({});
1154
+ const [isLoading, setIsLoading] = useState(true);
1155
+ const [error, setError] = useState(null);
1156
+ const [fetchTrigger, setFetchTrigger] = useState(0);
1157
+ const isFetchingRef = useRef(false);
1272
1158
  const logger2 = getRBACLogger();
1273
- const prevValuesRef = useRef3({ userId, organisationId, eventId, appId });
1159
+ const prevValuesRef = useRef({ userId, organisationId, eventId, appId });
1274
1160
  const orgId = organisationId || "";
1275
- useEffect9(() => {
1161
+ useEffect(() => {
1276
1162
  if (!userId) {
1277
1163
  return;
1278
1164
  }
@@ -1287,16 +1173,15 @@ function usePermissions(userId, organisationId, eventId, appId) {
1287
1173
  setError(null);
1288
1174
  }
1289
1175
  }, [userId, organisationId, error, orgId]);
1290
- useEffect9(() => {
1176
+ useEffect(() => {
1291
1177
  const paramsChanged = prevValuesRef.current.userId !== userId || prevValuesRef.current.organisationId !== organisationId || prevValuesRef.current.eventId !== eventId || prevValuesRef.current.appId !== appId;
1292
1178
  if (paramsChanged) {
1293
- if (prevValuesRef.current.appId !== appId) {
1294
- }
1179
+ if (prevValuesRef.current.appId !== appId) ;
1295
1180
  prevValuesRef.current = { userId, organisationId, eventId, appId };
1296
1181
  setFetchTrigger((prev) => prev + 1);
1297
1182
  }
1298
1183
  }, [userId, organisationId, eventId, appId, logger2]);
1299
- useEffect9(() => {
1184
+ useEffect(() => {
1300
1185
  const fetchPermissions = async () => {
1301
1186
  if (isFetchingRef.current) {
1302
1187
  return;
@@ -1343,25 +1228,25 @@ function usePermissions(userId, organisationId, eventId, appId) {
1343
1228
  };
1344
1229
  fetchPermissions();
1345
1230
  }, [fetchTrigger, userId, organisationId, eventId, appId]);
1346
- const hasPermission = useCallback8((permission) => {
1231
+ const hasPermission = useCallback((permission) => {
1347
1232
  if (permissions["*"]) {
1348
1233
  return true;
1349
1234
  }
1350
1235
  return permissions[permission] === true;
1351
1236
  }, [permissions]);
1352
- const hasAnyPermission = useCallback8((permissionList) => {
1237
+ const hasAnyPermission = useCallback((permissionList) => {
1353
1238
  if (permissions["*"]) {
1354
1239
  return true;
1355
1240
  }
1356
1241
  return permissionList.some((p) => permissions[p] === true);
1357
1242
  }, [permissions]);
1358
- const hasAllPermissions = useCallback8((permissionList) => {
1243
+ const hasAllPermissions = useCallback((permissionList) => {
1359
1244
  if (permissions["*"]) {
1360
1245
  return true;
1361
1246
  }
1362
1247
  return permissionList.every((p) => permissions[p] === true);
1363
1248
  }, [permissions]);
1364
- const refetch = useCallback8(async () => {
1249
+ const refetch = useCallback(async () => {
1365
1250
  if (isFetchingRef.current) {
1366
1251
  return;
1367
1252
  }
@@ -1395,7 +1280,7 @@ function usePermissions(userId, organisationId, eventId, appId) {
1395
1280
  isFetchingRef.current = false;
1396
1281
  }
1397
1282
  }, [userId, organisationId, eventId, appId]);
1398
- return useMemo9(() => ({
1283
+ return useMemo(() => ({
1399
1284
  permissions,
1400
1285
  isLoading,
1401
1286
  error,
@@ -1405,12 +1290,57 @@ function usePermissions(userId, organisationId, eventId, appId) {
1405
1290
  refetch
1406
1291
  }), [permissions, isLoading, error, hasPermission, hasAnyPermission, hasAllPermissions, refetch]);
1407
1292
  }
1408
-
1409
- // src/rbac/hooks/useResourcePermissions.ts
1410
- import { useMemo as useMemo10 } from "react";
1411
1293
  function useResourcePermissions(resource, options = {}) {
1412
1294
  const { enableRead = false, requireScope = true } = options;
1295
+ const logger2 = createLogger("ResourcePermissions");
1413
1296
  const { user, supabase } = useUnifiedAuth();
1297
+ const [isSuperAdminUser, setIsSuperAdminUser] = useState(null);
1298
+ const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(() => !!user?.id);
1299
+ const lastCheckedUserIdRef = useRef(null);
1300
+ const isCheckingRef = useRef(false);
1301
+ useEffect(() => {
1302
+ if (lastCheckedUserIdRef.current === user?.id && isSuperAdminUser !== null) {
1303
+ return;
1304
+ }
1305
+ if (isCheckingRef.current) {
1306
+ return;
1307
+ }
1308
+ const checkSuperAdminStatus = async () => {
1309
+ if (!user?.id) {
1310
+ setIsSuperAdminUser(false);
1311
+ setIsCheckingSuperAdmin(false);
1312
+ lastCheckedUserIdRef.current = null;
1313
+ return;
1314
+ }
1315
+ isCheckingRef.current = true;
1316
+ lastCheckedUserIdRef.current = user.id;
1317
+ const startTime = Date.now();
1318
+ setIsCheckingSuperAdmin(true);
1319
+ const timeoutId = setTimeout(() => {
1320
+ logger2.warn("useResourcePermissions", "Super admin check taking longer than 5 seconds", {
1321
+ userId: user?.id,
1322
+ elapsedMs: Date.now() - startTime
1323
+ });
1324
+ }, 5e3);
1325
+ try {
1326
+ const superAdminStatus = await isSuperAdmin(user.id);
1327
+ setIsSuperAdminUser(superAdminStatus);
1328
+ } catch (error2) {
1329
+ const elapsed = Date.now() - startTime;
1330
+ logger2.error("useResourcePermissions", "Error checking super admin status", {
1331
+ userId: user?.id,
1332
+ error: error2,
1333
+ elapsedMs: elapsed
1334
+ });
1335
+ setIsSuperAdminUser(false);
1336
+ } finally {
1337
+ clearTimeout(timeoutId);
1338
+ setIsCheckingSuperAdmin(false);
1339
+ isCheckingRef.current = false;
1340
+ }
1341
+ };
1342
+ checkSuperAdminStatus();
1343
+ }, [user?.id, logger2]);
1414
1344
  const { selectedOrganisation } = useOrganisations();
1415
1345
  let selectedEvent = null;
1416
1346
  try {
@@ -1421,70 +1351,79 @@ function useResourcePermissions(resource, options = {}) {
1421
1351
  const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
1422
1352
  supabase,
1423
1353
  selectedOrganisationId: selectedOrganisation?.id || null,
1424
- selectedEventId: selectedEvent?.event_id || null
1354
+ selectedEventId: selectedEvent?.event_id || null,
1355
+ selectedEventOrganisationId: selectedEvent?.organisation_id || null
1425
1356
  });
1426
1357
  const scope = resolvedScope || {
1427
1358
  organisationId: selectedOrganisation?.id || "",
1428
1359
  eventId: selectedEvent?.event_id || void 0,
1429
1360
  appId: void 0
1430
1361
  };
1431
- const pageId = scope.appId ? resource : void 0;
1362
+ const hasAppId = !!resolvedScope?.appId;
1363
+ const pageId = hasAppId ? resource : void 0;
1364
+ const isPagePermission = hasAppId && !!pageId;
1365
+ const createPermission = isPagePermission ? `create:page.${resource}` : `create:${resource}`;
1366
+ const updatePermission = isPagePermission ? `update:page.${resource}` : `update:${resource}`;
1367
+ const deletePermission = isPagePermission ? `delete:page.${resource}` : `delete:${resource}`;
1368
+ const readPermission = isPagePermission ? `read:page.${resource}` : `read:${resource}`;
1432
1369
  const { can: canCreateResult, isLoading: createLoading, error: createError } = useCan(
1433
1370
  user?.id || "",
1434
1371
  scope,
1435
- `create:${resource}`,
1372
+ createPermission,
1436
1373
  pageId,
1437
1374
  // Pass resource name as pageId when appId is available to enable page permission checks
1438
1375
  true,
1439
1376
  // useCache
1440
- null,
1441
- // precomputedSuperAdmin - not checked yet
1377
+ isSuperAdminUser,
1378
+ // precomputedSuperAdmin - null if checking, false/true if checked
1442
1379
  void 0
1443
1380
  // appName
1444
1381
  );
1445
1382
  const { can: canUpdateResult, isLoading: updateLoading, error: updateError } = useCan(
1446
1383
  user?.id || "",
1447
1384
  scope,
1448
- `update:${resource}`,
1385
+ updatePermission,
1449
1386
  pageId,
1450
1387
  // Pass resource name as pageId when appId is available to enable page permission checks
1451
1388
  true,
1452
1389
  // useCache
1453
- null,
1454
- // precomputedSuperAdmin - not checked yet
1390
+ isSuperAdminUser,
1391
+ // precomputedSuperAdmin - null if checking, false/true if checked
1455
1392
  void 0
1456
1393
  // appName
1457
1394
  );
1458
1395
  const { can: canDeleteResult, isLoading: deleteLoading, error: deleteError } = useCan(
1459
1396
  user?.id || "",
1460
1397
  scope,
1461
- `delete:${resource}`,
1398
+ deletePermission,
1462
1399
  pageId,
1463
1400
  // Pass resource name as pageId when appId is available to enable page permission checks
1464
1401
  true,
1465
1402
  // useCache
1466
- null,
1467
- // precomputedSuperAdmin - not checked yet
1403
+ isSuperAdminUser,
1404
+ // precomputedSuperAdmin - null if checking, false/true if checked
1468
1405
  void 0
1469
1406
  // appName
1470
1407
  );
1471
1408
  const { can: canReadResult, isLoading: readLoading, error: readError } = useCan(
1472
1409
  user?.id || "",
1473
1410
  scope,
1474
- `read:${resource}`,
1411
+ readPermission,
1475
1412
  pageId,
1476
1413
  // Pass resource name as pageId when appId is available to enable page permission checks
1477
1414
  true,
1478
1415
  // useCache
1479
- null,
1480
- // precomputedSuperAdmin - not checked yet
1416
+ isSuperAdminUser,
1417
+ // precomputedSuperAdmin - null if checking, false/true if checked
1481
1418
  void 0
1482
1419
  // appName
1483
1420
  );
1484
- const isLoading = useMemo10(() => {
1485
- return scopeLoading || createLoading || updateLoading || deleteLoading || enableRead && readLoading;
1486
- }, [scopeLoading, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
1487
- const error = useMemo10(() => {
1421
+ const isLoading = useMemo(() => {
1422
+ const waitingForScope = requireScope && scopeLoading;
1423
+ const waitingForSuperAdmin = isSuperAdminUser === null && isCheckingSuperAdmin;
1424
+ return waitingForScope || waitingForSuperAdmin || createLoading || updateLoading || deleteLoading || enableRead && readLoading;
1425
+ }, [scopeLoading, requireScope, isSuperAdminUser, isCheckingSuperAdmin, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
1426
+ const error = useMemo(() => {
1488
1427
  if (scopeError) return scopeError;
1489
1428
  if (createError) return createError;
1490
1429
  if (updateError) return updateError;
@@ -1492,39 +1431,49 @@ function useResourcePermissions(resource, options = {}) {
1492
1431
  if (enableRead && readError) return readError;
1493
1432
  return null;
1494
1433
  }, [scopeError, createError, updateError, deleteError, readError, enableRead]);
1495
- return useMemo10(() => ({
1496
- canCreate: (res) => {
1497
- if (res !== resource) {
1498
- return false;
1499
- }
1500
- return canCreateResult;
1501
- },
1502
- canUpdate: (res) => {
1503
- if (res !== resource) {
1504
- return false;
1505
- }
1506
- return canUpdateResult;
1507
- },
1508
- canDelete: (res) => {
1509
- if (res !== resource) {
1510
- return false;
1511
- }
1512
- return canDeleteResult;
1513
- },
1514
- canRead: (res) => {
1515
- if (!enableRead) {
1434
+ return useMemo(() => {
1435
+ const createSuperAdminAwarePermission = (result) => {
1436
+ if (isSuperAdminUser === true) {
1516
1437
  return true;
1517
1438
  }
1518
- if (res !== resource) {
1519
- return false;
1520
- }
1521
- return canReadResult;
1522
- },
1523
- scope,
1524
- isLoading,
1525
- error
1526
- }), [
1439
+ return result;
1440
+ };
1441
+ return {
1442
+ canCreate: (res) => {
1443
+ if (res !== resource) {
1444
+ return false;
1445
+ }
1446
+ return createSuperAdminAwarePermission(canCreateResult);
1447
+ },
1448
+ canUpdate: (res) => {
1449
+ if (res !== resource) {
1450
+ return false;
1451
+ }
1452
+ return createSuperAdminAwarePermission(canUpdateResult);
1453
+ },
1454
+ canDelete: (res) => {
1455
+ if (res !== resource) {
1456
+ return false;
1457
+ }
1458
+ return createSuperAdminAwarePermission(canDeleteResult);
1459
+ },
1460
+ canRead: (res) => {
1461
+ if (!enableRead) {
1462
+ return true;
1463
+ }
1464
+ if (res !== resource) {
1465
+ return false;
1466
+ }
1467
+ return createSuperAdminAwarePermission(canReadResult);
1468
+ },
1469
+ scope,
1470
+ isLoading: isCheckingSuperAdmin || isLoading,
1471
+ error
1472
+ };
1473
+ }, [
1527
1474
  resource,
1475
+ isSuperAdminUser,
1476
+ isCheckingSuperAdmin,
1528
1477
  canCreateResult,
1529
1478
  canUpdateResult,
1530
1479
  canDeleteResult,
@@ -1535,38 +1484,102 @@ function useResourcePermissions(resource, options = {}) {
1535
1484
  error
1536
1485
  ]);
1537
1486
  }
1538
-
1539
- // src/rbac/hooks/useRoleManagement.ts
1540
- import { useState as useState10, useCallback as useCallback9 } from "react";
1541
1487
  function useRoleManagement() {
1542
1488
  const { user, supabase } = useUnifiedAuth();
1543
- const [isLoading, setIsLoading] = useState10(false);
1544
- const [error, setError] = useState10(null);
1489
+ const [isLoading, setIsLoading] = useState(false);
1490
+ const [error, setError] = useState(null);
1545
1491
  if (!supabase) {
1546
1492
  throw new Error("useRoleManagement requires a Supabase client. Ensure UnifiedAuthProvider is configured.");
1547
1493
  }
1548
- const revokeEventAppRole = useCallback9(async (params) => {
1494
+ const revokeEventAppRole = useCallback(async (params) => {
1549
1495
  setIsLoading(true);
1550
1496
  setError(null);
1551
1497
  try {
1552
- const { data, error: rpcError } = await supabase.rpc("revoke_event_app_role", {
1498
+ const contextId = `${params.event_id}:${params.app_id}`;
1499
+ const rpcParams = {
1553
1500
  p_user_id: params.user_id,
1554
- p_organisation_id: params.organisation_id,
1555
- p_event_id: params.event_id,
1556
- p_app_id: params.app_id,
1557
- p_role: params.role,
1501
+ p_role_type: "event_app",
1502
+ p_role_name: params.role,
1503
+ p_context_id: contextId,
1558
1504
  p_revoked_by: params.revoked_by || user?.id || void 0
1559
- });
1505
+ };
1506
+ if (import.meta.env.MODE === "development") {
1507
+ console.log("[useRoleManagement] revokeEventAppRole called with:", rpcParams);
1508
+ }
1509
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", rpcParams);
1560
1510
  if (rpcError) {
1561
- throw new Error(rpcError.message || "Failed to revoke role");
1511
+ if (import.meta.env.MODE === "development") {
1512
+ console.error("[useRoleManagement] RPC error:", {
1513
+ message: rpcError.message,
1514
+ details: rpcError.details,
1515
+ hint: rpcError.hint,
1516
+ code: rpcError.code,
1517
+ fullError: rpcError
1518
+ });
1519
+ }
1520
+ const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
1521
+ throw new Error(errorMessage);
1522
+ }
1523
+ if (import.meta.env.MODE === "development") {
1524
+ console.log("[useRoleManagement] RPC response:", {
1525
+ data,
1526
+ error: rpcError,
1527
+ dataType: Array.isArray(data) ? "array" : typeof data,
1528
+ dataLength: Array.isArray(data) ? data.length : "N/A"
1529
+ });
1530
+ }
1531
+ if (!data || !Array.isArray(data) || data.length === 0) {
1532
+ const errorMsg = "No response from database - role revocation may have failed";
1533
+ if (import.meta.env.MODE === "development") {
1534
+ console.error("[useRoleManagement] Empty or null data response:", {
1535
+ data,
1536
+ dataType: typeof data,
1537
+ isArray: Array.isArray(data),
1538
+ length: Array.isArray(data) ? data.length : "N/A"
1539
+ });
1540
+ }
1541
+ throw new Error(errorMsg);
1542
+ }
1543
+ const result = data[0];
1544
+ if (import.meta.env.MODE === "development") {
1545
+ console.log("[useRoleManagement] RPC result:", {
1546
+ success: result?.success,
1547
+ message: result?.message,
1548
+ error_code: result?.error_code,
1549
+ revoked_count: result?.revoked_count,
1550
+ fullResult: result
1551
+ });
1552
+ }
1553
+ if (!result || result.success !== true) {
1554
+ const errorMessage = result?.message || result?.error_code || "Role revocation failed";
1555
+ if (import.meta.env.MODE === "development") {
1556
+ console.error("[useRoleManagement] Role revocation failed:", {
1557
+ result,
1558
+ errorMessage,
1559
+ fullData: data,
1560
+ rpcParams
1561
+ });
1562
+ }
1563
+ return {
1564
+ success: false,
1565
+ message: result?.message || void 0,
1566
+ error: errorMessage
1567
+ };
1562
1568
  }
1563
1569
  return {
1564
- success: data === true,
1565
- message: data === true ? "Role revoked successfully" : "No role found to revoke",
1566
- error: data === false ? "No matching role found" : void 0
1570
+ success: true,
1571
+ message: result.message || "Role revoked successfully",
1572
+ error: void 0
1567
1573
  };
1568
1574
  } catch (err) {
1569
1575
  const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1576
+ if (import.meta.env.MODE === "development") {
1577
+ console.error("[useRoleManagement] Exception in revokeEventAppRole:", {
1578
+ error: err,
1579
+ errorMessage,
1580
+ params
1581
+ });
1582
+ }
1570
1583
  setError(err instanceof Error ? err : new Error(errorMessage));
1571
1584
  return {
1572
1585
  success: false,
@@ -1575,8 +1588,8 @@ function useRoleManagement() {
1575
1588
  } finally {
1576
1589
  setIsLoading(false);
1577
1590
  }
1578
- }, [user?.id]);
1579
- const grantEventAppRole = useCallback9(async (params) => {
1591
+ }, [user?.id, supabase]);
1592
+ const grantEventAppRole = useCallback(async (params) => {
1580
1593
  setIsLoading(true);
1581
1594
  setError(null);
1582
1595
  try {
@@ -1615,7 +1628,7 @@ function useRoleManagement() {
1615
1628
  setIsLoading(false);
1616
1629
  }
1617
1630
  }, [user?.id]);
1618
- const revokeRoleById = useCallback9(async (roleId) => {
1631
+ const revokeRoleById = useCallback(async (roleId) => {
1619
1632
  setIsLoading(true);
1620
1633
  setError(null);
1621
1634
  try {
@@ -1632,13 +1645,28 @@ function useRoleManagement() {
1632
1645
  p_revoked_by: user?.id || void 0
1633
1646
  });
1634
1647
  if (rpcError) {
1635
- throw new Error(rpcError.message || "Failed to revoke role");
1648
+ const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
1649
+ throw new Error(errorMessage);
1636
1650
  }
1637
1651
  const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1652
+ if (!result) {
1653
+ return {
1654
+ success: false,
1655
+ error: void 0
1656
+ };
1657
+ }
1658
+ if (result.success === false) {
1659
+ const errorMessage = result.message || result.error_code || "Role revocation failed";
1660
+ return {
1661
+ success: false,
1662
+ message: result.message || void 0,
1663
+ error: errorMessage
1664
+ };
1665
+ }
1638
1666
  return {
1639
- success: result?.success === true,
1640
- message: result?.message || void 0,
1641
- error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
1667
+ success: true,
1668
+ message: result.message || "Role revoked successfully",
1669
+ error: void 0
1642
1670
  };
1643
1671
  } catch (err) {
1644
1672
  const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
@@ -1651,7 +1679,7 @@ function useRoleManagement() {
1651
1679
  setIsLoading(false);
1652
1680
  }
1653
1681
  }, [user?.id, supabase]);
1654
- const grantGlobalRole = useCallback9(async (params) => {
1682
+ const grantGlobalRole = useCallback(async (params) => {
1655
1683
  setIsLoading(true);
1656
1684
  setError(null);
1657
1685
  try {
@@ -1690,7 +1718,7 @@ function useRoleManagement() {
1690
1718
  setIsLoading(false);
1691
1719
  }
1692
1720
  }, [user?.id, supabase]);
1693
- const revokeGlobalRole = useCallback9(async (params) => {
1721
+ const revokeGlobalRole = useCallback(async (params) => {
1694
1722
  setIsLoading(true);
1695
1723
  setError(null);
1696
1724
  try {
@@ -1703,7 +1731,14 @@ function useRoleManagement() {
1703
1731
  p_revoked_by: params.revoked_by || user?.id || void 0
1704
1732
  });
1705
1733
  if (rpcError) {
1706
- throw new Error(rpcError.message || "Failed to revoke role");
1734
+ const errorParts = [
1735
+ rpcError.message,
1736
+ rpcError.details,
1737
+ rpcError.hint,
1738
+ rpcError.code ? `Error code: ${rpcError.code}` : null
1739
+ ].filter(Boolean);
1740
+ const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
1741
+ throw new Error(errorMessage);
1707
1742
  }
1708
1743
  const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1709
1744
  return {
@@ -1722,7 +1757,7 @@ function useRoleManagement() {
1722
1757
  setIsLoading(false);
1723
1758
  }
1724
1759
  }, [user?.id, supabase]);
1725
- const grantOrganisationRole = useCallback9(async (params) => {
1760
+ const grantOrganisationRole = useCallback(async (params) => {
1726
1761
  setIsLoading(true);
1727
1762
  setError(null);
1728
1763
  try {
@@ -1761,7 +1796,7 @@ function useRoleManagement() {
1761
1796
  setIsLoading(false);
1762
1797
  }
1763
1798
  }, [user?.id, supabase]);
1764
- const revokeOrganisationRole = useCallback9(async (params) => {
1799
+ const revokeOrganisationRole = useCallback(async (params) => {
1765
1800
  setIsLoading(true);
1766
1801
  setError(null);
1767
1802
  try {
@@ -1774,7 +1809,14 @@ function useRoleManagement() {
1774
1809
  p_revoked_by: params.revoked_by || user?.id || void 0
1775
1810
  });
1776
1811
  if (rpcError) {
1777
- throw new Error(rpcError.message || "Failed to revoke role");
1812
+ const errorParts = [
1813
+ rpcError.message,
1814
+ rpcError.details,
1815
+ rpcError.hint,
1816
+ rpcError.code ? `Error code: ${rpcError.code}` : null
1817
+ ].filter(Boolean);
1818
+ const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
1819
+ throw new Error(errorMessage);
1778
1820
  }
1779
1821
  const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1780
1822
  return {
@@ -1809,13 +1851,10 @@ function useRoleManagement() {
1809
1851
  error
1810
1852
  };
1811
1853
  }
1812
-
1813
- // src/rbac/hooks/useSecureSupabase.ts
1814
- import { useMemo as useMemo11, useRef as useRef4 } from "react";
1815
1854
  var secureClientCache = /* @__PURE__ */ new Map();
1816
1855
  var MAX_CACHE_SIZE = 5;
1817
- function getCacheKey(organisationId, eventId, appId, isSuperAdmin) {
1818
- return `${organisationId || "no-org"}-${eventId || "no-event"}-${appId || "no-app"}-${isSuperAdmin ? "super" : "regular"}`;
1856
+ function getCacheKey(organisationId, eventId, appId, isSuperAdmin2) {
1857
+ return `${organisationId || "no-org"}-${eventId || "no-event"}-${appId || "no-app"}-${isSuperAdmin2 ? "super" : "regular"}`;
1819
1858
  }
1820
1859
  function getSupabaseConfig() {
1821
1860
  const getEnvVar = (key) => {
@@ -1841,28 +1880,26 @@ function useSecureSupabase(baseClient) {
1841
1880
  const { selectedEvent } = eventsContext;
1842
1881
  const eventLoading = "eventLoading" in eventsContext ? eventsContext.eventLoading : false;
1843
1882
  const { superAdminContext } = useOrganisationSecurity();
1844
- const isSuperAdmin = superAdminContext.isSuperAdmin;
1883
+ const isSuperAdmin2 = superAdminContext.isSuperAdmin;
1845
1884
  const { resolvedScope } = useResolvedScope({
1846
1885
  supabase: authSupabase || null,
1847
1886
  selectedOrganisationId: selectedOrganisation?.id || null,
1848
- selectedEventId: selectedEvent?.event_id || null
1887
+ selectedEventId: selectedEvent?.event_id || null,
1888
+ selectedEventOrganisationId: selectedEvent?.organisation_id || null
1849
1889
  });
1850
- const prevContextRef = useRef4({
1890
+ const prevContextRef = useRef({
1851
1891
  organisationId: void 0,
1852
1892
  eventId: void 0,
1853
1893
  appId: void 0
1854
1894
  });
1855
- return useMemo11(() => {
1856
- if (eventLoading) {
1857
- return baseClient || authSupabase || null;
1858
- }
1895
+ return useMemo(() => {
1859
1896
  const organisationId = resolvedScope?.organisationId;
1860
1897
  const eventId = resolvedScope?.eventId || selectedEvent?.event_id;
1861
1898
  const appId = resolvedScope?.appId;
1862
- const canCreateSecureClient = user?.id && (isSuperAdmin || organisationId);
1899
+ const canCreateSecureClient = user?.id && (isSuperAdmin2 || organisationId);
1863
1900
  if (canCreateSecureClient) {
1864
1901
  prevContextRef.current = { organisationId, eventId, appId };
1865
- const cacheKey = getCacheKey(organisationId, eventId, appId, isSuperAdmin);
1902
+ const cacheKey = getCacheKey(organisationId, eventId, appId, isSuperAdmin2);
1866
1903
  const cachedClient = secureClientCache.get(cacheKey);
1867
1904
  if (cachedClient) {
1868
1905
  return cachedClient.getClient();
@@ -1875,14 +1912,14 @@ function useSecureSupabase(baseClient) {
1875
1912
  return baseClient || authSupabase || null;
1876
1913
  }
1877
1914
  try {
1878
- const effectiveOrganisationId = isSuperAdmin ? organisationId || null : organisationId;
1915
+ const effectiveOrganisationId = isSuperAdmin2 ? organisationId || null : organisationId;
1879
1916
  const baseForSecureClient = baseClient || authSupabase || null;
1880
1917
  const secureClient = baseForSecureClient ? fromSupabaseClient(
1881
1918
  baseForSecureClient,
1882
1919
  effectiveOrganisationId ?? null,
1883
1920
  eventId,
1884
1921
  appId,
1885
- isSuperAdmin
1922
+ isSuperAdmin2
1886
1923
  ) : createSecureClient(
1887
1924
  config.url,
1888
1925
  config.key,
@@ -1891,7 +1928,7 @@ function useSecureSupabase(baseClient) {
1891
1928
  eventId,
1892
1929
  appId,
1893
1930
  // appId is string | undefined, UUID is string alias
1894
- isSuperAdmin
1931
+ isSuperAdmin2
1895
1932
  // Pass super admin status for conditional filtering
1896
1933
  );
1897
1934
  secureClientCache.set(cacheKey, secureClient);
@@ -1915,31 +1952,10 @@ function useSecureSupabase(baseClient) {
1915
1952
  selectedEvent?.event_id,
1916
1953
  user?.id,
1917
1954
  eventLoading,
1918
- isSuperAdmin,
1955
+ isSuperAdmin2,
1919
1956
  baseClient,
1920
1957
  authSupabase
1921
1958
  ]);
1922
1959
  }
1923
1960
 
1924
- export {
1925
- SECURE_CLIENT_SYMBOL,
1926
- isSecureClient,
1927
- warnIfInsecureClient,
1928
- SecureSupabaseClient,
1929
- createSecureClient,
1930
- fromSupabaseClient,
1931
- useResolvedScope,
1932
- useRBAC,
1933
- useAccessLevel,
1934
- useCachedPermissions,
1935
- scopeEqual,
1936
- useCan,
1937
- useHasAllPermissions,
1938
- useHasAnyPermission,
1939
- useMultiplePermissions,
1940
- usePermissions,
1941
- useResourcePermissions,
1942
- useRoleManagement,
1943
- useSecureSupabase
1944
- };
1945
- //# sourceMappingURL=chunk-NN6WWZ5U.js.map
1961
+ export { Button, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };