@jmruthers/pace-core 0.5.74 → 0.5.76

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 (369) hide show
  1. package/dist/DataTable-4GAVPIEG.js +120 -0
  2. package/dist/{PublicLoadingSpinner-DLpF5bbs.d.ts → PublicLoadingSpinner-BiNER8F5.d.ts} +30 -19
  3. package/dist/RBACService-C4udt_Zp.d.ts +528 -0
  4. package/dist/{UnifiedAuthProvider-K4NRGXL4.js → UnifiedAuthProvider-3NKDOSOK.js} +6 -4
  5. package/dist/UnifiedAuthProvider-Bj6YCf7c.d.ts +113 -0
  6. package/dist/chunk-5F3NDPJV.js +232 -0
  7. package/dist/chunk-5F3NDPJV.js.map +1 -0
  8. package/dist/chunk-A4FUBC7B.js +17 -0
  9. package/dist/chunk-A4FUBC7B.js.map +1 -0
  10. package/dist/{chunk-SMJZMKYN.js → chunk-A6HBIY5P.js} +2 -11
  11. package/dist/{chunk-SMJZMKYN.js.map → chunk-A6HBIY5P.js.map} +1 -1
  12. package/dist/{chunk-LVQ26TCN.js → chunk-AFGTSUAD.js} +43 -127
  13. package/dist/chunk-AFGTSUAD.js.map +1 -0
  14. package/dist/{chunk-BKVGJVUR.js → chunk-K34IM5CT.js} +497 -33
  15. package/dist/chunk-K34IM5CT.js.map +1 -0
  16. package/dist/{chunk-UJMCGBLS.js → chunk-KHJS6VIA.js} +203 -41
  17. package/dist/chunk-KHJS6VIA.js.map +1 -0
  18. package/dist/{chunk-ORSMVXO2.js → chunk-KK73ZB4E.js} +9 -14
  19. package/dist/chunk-KK73ZB4E.js.map +1 -0
  20. package/dist/{chunk-VKOCWWVY.js → chunk-L3RV2ALE.js} +1 -6
  21. package/dist/{chunk-VKOCWWVY.js.map → chunk-L3RV2ALE.js.map} +1 -1
  22. package/dist/chunk-LW7MMEAQ.js +59 -0
  23. package/dist/chunk-LW7MMEAQ.js.map +1 -0
  24. package/dist/{chunk-IHMMNKNA.js → chunk-M5IWZRBT.js} +5118 -1864
  25. package/dist/chunk-M5IWZRBT.js.map +1 -0
  26. package/dist/{chunk-DG5Z55HH.js → chunk-NTNILOBC.js} +7 -9
  27. package/dist/chunk-NTNILOBC.js.map +1 -0
  28. package/dist/chunk-PYUXFQJ3.js +11 -0
  29. package/dist/chunk-PYUXFQJ3.js.map +1 -0
  30. package/dist/chunk-URUTVZ7N.js +27 -0
  31. package/dist/chunk-URUTVZ7N.js.map +1 -0
  32. package/dist/chunk-WN6XJWOS.js +2468 -0
  33. package/dist/chunk-WN6XJWOS.js.map +1 -0
  34. package/dist/{chunk-3SP4P7NS.js → chunk-XLZ7U46Z.js} +59 -1
  35. package/dist/chunk-XLZ7U46Z.js.map +1 -0
  36. package/dist/{chunk-H2TNUICK.js → chunk-Y6TXWPJO.js} +50 -50
  37. package/dist/chunk-Y6TXWPJO.js.map +1 -0
  38. package/dist/{chunk-YNUBMSMV.js → chunk-YCKPEMJA.js} +186 -263
  39. package/dist/chunk-YCKPEMJA.js.map +1 -0
  40. package/dist/components.d.ts +4 -5
  41. package/dist/components.js +35 -41
  42. package/dist/components.js.map +1 -1
  43. package/dist/hooks.d.ts +20 -43
  44. package/dist/hooks.js +13 -12
  45. package/dist/hooks.js.map +1 -1
  46. package/dist/index.d.ts +156 -10
  47. package/dist/index.js +193 -96
  48. package/dist/index.js.map +1 -1
  49. package/dist/{organisation-t-vvQC3g.d.ts → organisation-BtshODVF.d.ts} +4 -3
  50. package/dist/providers.d.ts +27 -38
  51. package/dist/providers.js +33 -23
  52. package/dist/rbac/index.d.ts +114 -5
  53. package/dist/rbac/index.js +15 -15
  54. package/dist/styles/index.js +2 -2
  55. package/dist/theming/runtime.js +1 -3
  56. package/dist/types.d.ts +3 -3
  57. package/dist/types.js +1 -1
  58. package/dist/types.js.map +1 -1
  59. package/dist/{unified-CMPjE_fv.d.ts → unified-CM7T0aTK.d.ts} +1 -1
  60. package/dist/useInactivityTracker-MRUU55XI.js +10 -0
  61. package/dist/{usePublicRouteParams-Ua1Vz-HG.d.ts → usePublicRouteParams-B-CumWRc.d.ts} +3 -3
  62. package/dist/utils.js +7 -9
  63. package/dist/utils.js.map +1 -1
  64. package/dist/validation.d.ts +1 -1
  65. package/docs/TERMINOLOGY.md +231 -0
  66. package/docs/api/classes/ColumnFactory.md +1 -1
  67. package/docs/api/classes/ErrorBoundary.md +1 -1
  68. package/docs/api/classes/InvalidScopeError.md +1 -1
  69. package/docs/api/classes/MissingUserContextError.md +1 -1
  70. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  71. package/docs/api/classes/PermissionDeniedError.md +1 -1
  72. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  73. package/docs/api/classes/RBACAuditManager.md +1 -1
  74. package/docs/api/classes/RBACCache.md +1 -1
  75. package/docs/api/classes/RBACEngine.md +1 -1
  76. package/docs/api/classes/RBACError.md +1 -1
  77. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  78. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  79. package/docs/api/classes/StorageUtils.md +1 -1
  80. package/docs/api/enums/FileCategory.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +1 -1
  82. package/docs/api/interfaces/ButtonProps.md +3 -3
  83. package/docs/api/interfaces/CardProps.md +2 -2
  84. package/docs/api/interfaces/ColorPalette.md +1 -1
  85. package/docs/api/interfaces/ColorShade.md +1 -1
  86. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  87. package/docs/api/interfaces/DataTableAction.md +1 -1
  88. package/docs/api/interfaces/DataTableColumn.md +1 -1
  89. package/docs/api/interfaces/DataTableProps.md +1 -1
  90. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  91. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  92. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  93. package/docs/api/interfaces/EventLogoProps.md +2 -2
  94. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  95. package/docs/api/interfaces/FileMetadata.md +1 -1
  96. package/docs/api/interfaces/FileReference.md +1 -1
  97. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  98. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  99. package/docs/api/interfaces/FileUploadProps.md +1 -1
  100. package/docs/api/interfaces/FooterProps.md +1 -1
  101. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  102. package/docs/api/interfaces/InputProps.md +2 -2
  103. package/docs/api/interfaces/LabelProps.md +1 -1
  104. package/docs/api/interfaces/LoginFormProps.md +1 -1
  105. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  106. package/docs/api/interfaces/NavigationContextType.md +1 -1
  107. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  108. package/docs/api/interfaces/NavigationItem.md +1 -1
  109. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  110. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  111. package/docs/api/interfaces/Organisation.md +1 -1
  112. package/docs/api/interfaces/OrganisationContextType.md +28 -17
  113. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  114. package/docs/api/interfaces/OrganisationProviderProps.md +2 -2
  115. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  116. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  117. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  118. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  119. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  120. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  121. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  122. package/docs/api/interfaces/PaletteData.md +1 -1
  123. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  124. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  125. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  126. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +2 -2
  127. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  130. package/docs/api/interfaces/RBACConfig.md +1 -1
  131. package/docs/api/interfaces/RBACContextType.md +5 -11
  132. package/docs/api/interfaces/RBACLogger.md +1 -1
  133. package/docs/api/interfaces/RBACProviderProps.md +1 -1
  134. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  135. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  136. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  137. package/docs/api/interfaces/RouteConfig.md +1 -1
  138. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  139. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  140. package/docs/api/interfaces/StorageConfig.md +1 -1
  141. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  142. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  143. package/docs/api/interfaces/StorageListOptions.md +1 -1
  144. package/docs/api/interfaces/StorageListResult.md +1 -1
  145. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  146. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  147. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  148. package/docs/api/interfaces/StyleImport.md +1 -1
  149. package/docs/api/interfaces/SwitchProps.md +1 -1
  150. package/docs/api/interfaces/ToastActionElement.md +1 -1
  151. package/docs/api/interfaces/ToastProps.md +1 -1
  152. package/docs/api/interfaces/UnifiedAuthContextType.md +524 -440
  153. package/docs/api/interfaces/UnifiedAuthProviderProps.md +14 -14
  154. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  155. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  159. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  160. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  161. package/docs/api/interfaces/UseResolvedScopeOptions.md +47 -0
  162. package/docs/api/interfaces/UseResolvedScopeReturn.md +47 -0
  163. package/docs/api/interfaces/UserEventAccess.md +11 -11
  164. package/docs/api/interfaces/UserMenuProps.md +1 -1
  165. package/docs/api/interfaces/UserProfile.md +1 -1
  166. package/docs/api/modules.md +234 -61
  167. package/docs/api-reference/providers.md +26 -7
  168. package/docs/architecture/services.md +30 -32
  169. package/docs/best-practices/README.md +20 -0
  170. package/docs/best-practices/accessibility.md +566 -0
  171. package/docs/best-practices/performance-expansion.md +473 -0
  172. package/docs/breaking-changes.md +2 -5
  173. package/docs/core-concepts/authentication.md +15 -7
  174. package/docs/documentation-index.md +1 -1
  175. package/docs/documentation-templates.md +539 -0
  176. package/docs/getting-started/quick-start.md +16 -66
  177. package/docs/implementation-guides/component-styling.md +410 -0
  178. package/docs/implementation-guides/data-tables.md +1 -1
  179. package/docs/migration/service-architecture.md +121 -260
  180. package/docs/rbac/README-rbac-rls-integration.md +48 -38
  181. package/docs/style-guide.md +39 -0
  182. package/{src/rbac/examples → examples/RBAC}/CompleteRBACExample.tsx +3 -2
  183. package/{src/rbac/examples → examples/RBAC}/EventBasedApp.tsx +5 -4
  184. package/{src/components/examples → examples/RBAC}/PermissionExample.tsx +7 -6
  185. package/examples/RBAC/__tests__/PermissionExample.test.tsx +150 -0
  186. package/examples/RBAC/index.ts +13 -0
  187. package/examples/README.md +37 -0
  188. package/examples/index.ts +22 -0
  189. package/{src/examples → examples/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
  190. package/{src/examples → examples/public-pages}/PublicEventPage.tsx +1 -1
  191. package/{src/examples → examples/public-pages}/PublicPageApp.tsx +1 -1
  192. package/{src/examples → examples/public-pages}/PublicPageUsageExample.tsx +1 -1
  193. package/examples/public-pages/__tests__/PublicPageUsageExample.test.tsx +159 -0
  194. package/examples/public-pages/index.ts +14 -0
  195. package/package.json +22 -18
  196. package/src/__tests__/TEST_GUIDE_CURSOR.md +940 -9
  197. package/src/__tests__/helpers/README.md +255 -0
  198. package/src/__tests__/helpers/index.ts +62 -0
  199. package/src/__tests__/helpers/supabaseMock.ts +75 -5
  200. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -8
  201. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +17 -6
  202. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +73 -9
  203. package/src/components/DataTable/components/DataTableCore.tsx +280 -475
  204. package/src/components/DataTable/components/UnifiedTableBody.tsx +120 -153
  205. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +55 -0
  206. package/src/components/DataTable/components/index.ts +1 -2
  207. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +208 -275
  208. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +254 -0
  209. package/src/components/DataTable/core/index.ts +1 -8
  210. package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +45 -0
  211. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +117 -0
  212. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +525 -0
  213. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +570 -0
  214. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +214 -0
  215. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +224 -0
  216. package/src/components/DataTable/hooks/index.ts +6 -0
  217. package/src/components/DataTable/hooks/useColumnReordering.ts +1 -0
  218. package/src/components/DataTable/hooks/useDataTablePermissions.ts +149 -0
  219. package/src/components/DataTable/hooks/useDataTableState.ts +12 -6
  220. package/src/components/DataTable/hooks/useHierarchicalState.ts +26 -8
  221. package/src/components/DataTable/hooks/useTableColumns.ts +153 -0
  222. package/src/components/DataTable/index.ts +1 -9
  223. package/src/components/DataTable/utils/__tests__/COVERAGE_NOTE.md +89 -0
  224. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +3 -6
  225. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +462 -0
  226. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +247 -0
  227. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +8 -6
  228. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +466 -0
  229. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +265 -0
  230. package/src/components/DataTable/utils/errorHandling.ts +52 -460
  231. package/src/components/DataTable/utils/exportUtils.ts +46 -15
  232. package/src/components/DataTable/utils/hierarchicalSorting.ts +50 -3
  233. package/src/components/DataTable/utils/hierarchicalUtils.ts +167 -34
  234. package/src/components/DataTable/utils/index.ts +5 -0
  235. package/src/components/DataTable/utils/rowUtils.ts +68 -0
  236. package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +71 -0
  237. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +122 -0
  238. package/src/components/EventSelector/EventSelector.test.tsx +672 -0
  239. package/src/components/EventSelector/EventSelector.tsx +1 -1
  240. package/src/components/Header/Header.test.tsx +35 -1
  241. package/src/components/Header/Header.tsx +3 -1
  242. package/src/components/Label/__tests__/Label.test.tsx +434 -0
  243. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -3
  244. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +24 -4
  245. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +3 -2
  246. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +190 -0
  247. package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +185 -0
  248. package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +313 -0
  249. package/src/components/Select/Select.test.tsx +143 -120
  250. package/src/components/Select/Select.tsx +47 -212
  251. package/src/components/Select/hooks.ts +36 -1
  252. package/src/components/Select/index.ts +2 -1
  253. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +220 -0
  254. package/src/hooks/__tests__/useIsMobile.unit.test.ts +117 -0
  255. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +295 -0
  256. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +29 -19
  257. package/src/hooks/__tests__/useRBAC.unit.test.ts +7 -3
  258. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +115 -19
  259. package/src/hooks/services/__tests__/useServiceHooks.test.tsx +137 -0
  260. package/src/hooks/useEventTheme.test.ts +350 -0
  261. package/src/hooks/useEventTheme.ts +1 -1
  262. package/src/hooks/useEvents.ts +61 -0
  263. package/src/hooks/useOrganisationSecurity.test.ts +4 -4
  264. package/src/hooks/useOrganisationSecurity.ts +2 -2
  265. package/src/hooks/useOrganisations.ts +64 -0
  266. package/src/hooks/useSecureDataAccess.test.ts +37 -30
  267. package/src/hooks/useSecureDataAccess.ts +2 -2
  268. package/src/index.ts +18 -3
  269. package/src/providers/AuthProvider.tsx +8 -292
  270. package/src/providers/EventProvider.tsx +15 -425
  271. package/src/providers/InactivityProvider.tsx +8 -231
  272. package/src/providers/OrganisationProvider.test.simple.tsx +3 -2
  273. package/src/providers/OrganisationProvider.tsx +11 -890
  274. package/src/providers/UnifiedAuthProvider.tsx +8 -320
  275. package/src/providers/__tests__/AuthProvider.test.tsx +18 -17
  276. package/src/providers/__tests__/EventProvider.test.tsx +253 -2
  277. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +65 -0
  278. package/src/providers/__tests__/InactivityProvider.test.tsx +46 -114
  279. package/src/providers/__tests__/OrganisationProvider.test.tsx +313 -3
  280. package/src/providers/__tests__/ProviderLifecycle.test.tsx +341 -0
  281. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +383 -2
  282. package/src/providers/index.ts +8 -7
  283. package/src/providers/services/EventServiceProvider.tsx +3 -0
  284. package/src/providers/services/UnifiedAuthProvider.tsx +3 -0
  285. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +437 -0
  286. package/src/rbac/hooks/index.ts +2 -0
  287. package/src/rbac/hooks/usePermissions.test.ts +296 -0
  288. package/src/rbac/hooks/useRBAC.test.ts +9 -5
  289. package/src/rbac/hooks/useRBAC.ts +3 -3
  290. package/src/rbac/hooks/useResolvedScope.ts +232 -0
  291. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +688 -0
  292. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +507 -0
  293. package/src/services/AuthService.ts +19 -4
  294. package/src/services/__tests__/AuthService.test.ts +288 -0
  295. package/src/services/__tests__/InactivityService.lifecycle.test.ts +411 -0
  296. package/src/services/__tests__/OrganisationService.pagination.test.ts +375 -0
  297. package/src/styles/core.css +2 -0
  298. package/src/types/__tests__/README.md +114 -0
  299. package/src/types/__tests__/guards.test.ts +246 -0
  300. package/src/types/__tests__/validation.test.ts +731 -0
  301. package/src/types/guards.ts +1 -0
  302. package/src/types/organisation.ts +3 -2
  303. package/src/utils/__tests__/file-reference.test.ts +383 -0
  304. package/src/utils/__tests__/performanceBenchmark.test.ts +175 -0
  305. package/src/utils/appNameResolver.test.ts +54 -0
  306. package/src/validation/__tests__/csrf.unit.test.ts +63 -0
  307. package/src/validation/__tests__/passwordSchema.unit.test.ts +105 -0
  308. package/src/validation/__tests__/sanitization.unit.test.ts +250 -0
  309. package/src/validation/__tests__/schemaUtils.unit.test.ts +451 -0
  310. package/src/validation/__tests__/user.unit.test.ts +440 -0
  311. package/dist/DataTable-2QR5TER5.js +0 -102
  312. package/dist/RBACProvider-BO4ilsQB.d.ts +0 -63
  313. package/dist/UnifiedAuthProvider-D02AMXgO.d.ts +0 -103
  314. package/dist/chunk-3SP4P7NS.js.map +0 -1
  315. package/dist/chunk-B5LK25HV.js +0 -953
  316. package/dist/chunk-B5LK25HV.js.map +0 -1
  317. package/dist/chunk-BKVGJVUR.js.map +0 -1
  318. package/dist/chunk-C5Q5LRU5.js +0 -5691
  319. package/dist/chunk-C5Q5LRU5.js.map +0 -1
  320. package/dist/chunk-CDDYJCYU.js +0 -79
  321. package/dist/chunk-CDDYJCYU.js.map +0 -1
  322. package/dist/chunk-DG5Z55HH.js.map +0 -1
  323. package/dist/chunk-H2TNUICK.js.map +0 -1
  324. package/dist/chunk-IHMMNKNA.js.map +0 -1
  325. package/dist/chunk-LVQ26TCN.js.map +0 -1
  326. package/dist/chunk-ORSMVXO2.js.map +0 -1
  327. package/dist/chunk-TYHR5X4W.js +0 -33
  328. package/dist/chunk-TYHR5X4W.js.map +0 -1
  329. package/dist/chunk-UJMCGBLS.js.map +0 -1
  330. package/dist/chunk-V6BHACCH.js +0 -17
  331. package/dist/chunk-V6BHACCH.js.map +0 -1
  332. package/dist/chunk-YNUBMSMV.js.map +0 -1
  333. package/dist/eventContext-BBA42P6G.js +0 -14
  334. package/dist/rbac/cli/policy-manager.js +0 -278
  335. package/dist/rbac/cli/policy-manager.js.map +0 -1
  336. package/docs/api/interfaces/EventContextType.md +0 -96
  337. package/docs/api/interfaces/EventProviderProps.md +0 -19
  338. package/docs/documentation-style-checklist.md +0 -294
  339. package/src/components/DataTable/components/DataTableBody.tsx +0 -488
  340. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -144
  341. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -515
  342. package/src/components/DataTable/core/ActionManager.ts +0 -235
  343. package/src/components/DataTable/core/ColumnManager.ts +0 -205
  344. package/src/components/DataTable/core/DataManager.ts +0 -188
  345. package/src/components/DataTable/core/DataTableContext.tsx +0 -181
  346. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -264
  347. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  348. package/src/components/DataTable/core/StateManager.ts +0 -311
  349. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -634
  350. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -519
  351. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -714
  352. package/src/components/DataTable/core/interfaces.ts +0 -338
  353. package/src/components/DataTable/utils/debugTools.ts +0 -583
  354. package/src/components/Select/Select.bug-test.tsx +0 -69
  355. package/src/components/Select/Select.refactored.tsx +0 -497
  356. package/src/providers/OrganisationProvider.test.tsx +0 -164
  357. package/src/providers/UnifiedAuthProvider.test.tsx +0 -124
  358. package/src/providers/__tests__/AuthProvider.test.tsx.backup +0 -771
  359. package/src/providers/__tests__/EventProvider.test.tsx.backup +0 -824
  360. package/src/providers/__tests__/OrganisationProvider.test.tsx.backup +0 -820
  361. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup +0 -911
  362. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx.backup2 +0 -166
  363. package/src/rbac/cli/__tests__/policy-manager.test.ts +0 -339
  364. package/src/rbac/cli/policy-manager.ts +0 -443
  365. package/dist/{DataTable-2QR5TER5.js.map → DataTable-4GAVPIEG.js.map} +0 -0
  366. package/dist/{UnifiedAuthProvider-K4NRGXL4.js.map → UnifiedAuthProvider-3NKDOSOK.js.map} +0 -0
  367. package/dist/{eventContext-BBA42P6G.js.map → useInactivityTracker-MRUU55XI.js.map} +0 -0
  368. package/dist/{validation-PM_iOaTI.d.ts → validation-D8VcbTzC.d.ts} +2 -2
  369. /package/src/utils/{appNameResolver.test.ts.backup → appNameResolver.test 2.ts} +0 -0
@@ -598,4 +598,300 @@ describe('usePermissions Hook', () => {
598
598
  expect(end - start).toBeLessThan(100); // Should complete in under 100ms
599
599
  });
600
600
  });
601
+
602
+ describe('[integration] Cache Invalidation', () => {
603
+ it('refetches after cache invalidation', async () => {
604
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
605
+
606
+ await waitFor(() => {
607
+ expect(result.current.isLoading).toBe(false);
608
+ });
609
+
610
+ expect(result.current.permissions).toEqual(mockPermissionMap);
611
+
612
+ // Invalidate and refetch
613
+ const newPermissions = { ...mockPermissionMap, 'new:permission': true };
614
+ mockGetPermissionMap.mockResolvedValue(newPermissions);
615
+ result.current.refetch();
616
+
617
+ await waitFor(() => {
618
+ expect(result.current.permissions).toEqual(newPermissions);
619
+ });
620
+ });
621
+
622
+ it('handles cache expiration gracefully', async () => {
623
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
624
+
625
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
626
+
627
+ await waitFor(() => {
628
+ expect(result.current.isLoading).toBe(false);
629
+ });
630
+
631
+ // First fetch should be cached, second should refetch
632
+ const callCount = mockGetPermissionMap.mock.calls.length;
633
+ result.current.refetch();
634
+
635
+ await waitFor(() => {
636
+ expect(mockGetPermissionMap).toHaveBeenCalledTimes(callCount + 1);
637
+ });
638
+ });
639
+
640
+ it('maintains consistent permissions across multiple refetches', async () => {
641
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
642
+
643
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
644
+
645
+ await waitFor(() => {
646
+ expect(result.current.isLoading).toBe(false);
647
+ });
648
+
649
+ // Multiple refetches should maintain consistency
650
+ result.current.refetch();
651
+ await waitFor(() => expect(mockGetPermissionMap).toHaveBeenCalled());
652
+
653
+ result.current.refetch();
654
+ await waitFor(() => expect(mockGetPermissionMap).toHaveBeenCalled());
655
+ });
656
+ });
657
+
658
+ describe('[integration] Concurrent Operations', () => {
659
+ it('handles concurrent permission checks', async () => {
660
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
661
+
662
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
663
+
664
+ await waitFor(() => {
665
+ expect(result.current.isLoading).toBe(false);
666
+ });
667
+
668
+ // Simulate concurrent permission checks
669
+ const promises = [];
670
+ for (let i = 0; i < 10; i++) {
671
+ promises.push(
672
+ Promise.resolve(result.current.hasPermission('read:users'))
673
+ );
674
+ }
675
+
676
+ const results = await Promise.all(promises);
677
+ expect(results.every(r => r === true)).toBe(true);
678
+ });
679
+
680
+ it('handles rapid scope changes without errors', async () => {
681
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
682
+
683
+ const { result, rerender } = renderHook(
684
+ ({ userId, scope }) => usePermissions(userId, scope),
685
+ {
686
+ initialProps: { userId: mockUserId, scope: mockScope }
687
+ }
688
+ );
689
+
690
+ await waitFor(() => {
691
+ expect(result.current.isLoading).toBe(false);
692
+ });
693
+
694
+ // Rapid scope changes
695
+ const scopes = [
696
+ { ...mockScope, eventId: 'event-1' },
697
+ { ...mockScope, eventId: 'event-2' },
698
+ { ...mockScope, eventId: 'event-3' }
699
+ ];
700
+
701
+ for (const scope of scopes) {
702
+ rerender({ userId: mockUserId, scope });
703
+ await waitFor(() => {
704
+ expect(result.current.isLoading).toBe(false);
705
+ }, { timeout: 100 });
706
+ }
707
+
708
+ expect(result.current.error).toBeNull();
709
+ });
710
+
711
+ it('handles mixed permission and refetch operations', async () => {
712
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
713
+
714
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
715
+
716
+ await waitFor(() => {
717
+ expect(result.current.isLoading).toBe(false);
718
+ });
719
+
720
+ // Mix permission checks with refetch
721
+ result.current.hasPermission('read:users');
722
+ result.current.refetch();
723
+ result.current.hasAnyPermission(['read:users', 'create:users']);
724
+ result.current.refetch();
725
+ result.current.hasAllPermissions(['read:users']);
726
+
727
+ await waitFor(() => {
728
+ expect(mockGetPermissionMap).toHaveBeenCalled();
729
+ });
730
+ });
731
+ });
732
+
733
+ describe('[integration] Permission Resolution Edge Cases', () => {
734
+ it('handles organization context changes', async () => {
735
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
736
+
737
+ const { result, rerender } = renderHook(
738
+ ({ userId, scope }) => usePermissions(userId, scope),
739
+ {
740
+ initialProps: { userId: mockUserId, scope: mockScope }
741
+ }
742
+ );
743
+
744
+ await waitFor(() => {
745
+ expect(result.current.isLoading).toBe(false);
746
+ });
747
+
748
+ // Change organization
749
+ const newScope = { ...mockScope, organisationId: 'org-456' };
750
+ rerender({ userId: mockUserId, scope: newScope });
751
+
752
+ await waitFor(() => {
753
+ expect(mockGetPermissionMap).toHaveBeenCalledTimes(2);
754
+ });
755
+ });
756
+
757
+ it('handles event context changes', async () => {
758
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
759
+
760
+ const { result, rerender } = renderHook(
761
+ ({ userId, scope }) => usePermissions(userId, scope),
762
+ {
763
+ initialProps: { userId: mockUserId, scope: mockScope }
764
+ }
765
+ );
766
+
767
+ await waitFor(() => {
768
+ expect(result.current.isLoading).toBe(false);
769
+ });
770
+
771
+ // Change event
772
+ const newScope = { ...mockScope, eventId: 'event-456' };
773
+ rerender({ userId: mockUserId, scope: newScope });
774
+
775
+ await waitFor(() => {
776
+ expect(mockGetPermissionMap).toHaveBeenCalledTimes(2);
777
+ });
778
+ });
779
+
780
+ it('handles permission resolution with partial scope', async () => {
781
+ const partialScope = { organisationId: mockScope.organisationId };
782
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
783
+
784
+ const { result } = renderHook(() => usePermissions(mockUserId, partialScope));
785
+
786
+ await waitFor(() => {
787
+ expect(result.current.isLoading).toBe(false);
788
+ });
789
+
790
+ expect(result.current.permissions).toEqual(mockPermissionMap);
791
+ });
792
+ });
793
+
794
+ describe('[integration] Error Recovery', () => {
795
+ it('recovers from transient errors', async () => {
796
+ mockGetPermissionMap
797
+ .mockRejectedValueOnce(new Error('Transient error'))
798
+ .mockResolvedValueOnce(mockPermissionMap);
799
+
800
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
801
+
802
+ await waitFor(() => {
803
+ expect(result.current.error).toBeDefined();
804
+ });
805
+
806
+ result.current.refetch();
807
+
808
+ await waitFor(() => {
809
+ expect(result.current.error).toBeNull();
810
+ expect(result.current.permissions).toEqual(mockPermissionMap);
811
+ });
812
+ });
813
+
814
+ it('handles network timeout gracefully', async () => {
815
+ mockGetPermissionMap.mockImplementation(
816
+ () => new Promise((_, reject) =>
817
+ setTimeout(() => reject(new Error('Timeout')), 100)
818
+ )
819
+ );
820
+
821
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
822
+
823
+ await waitFor(() => {
824
+ expect(result.current.isLoading).toBe(false);
825
+ expect(result.current.error).toBeDefined();
826
+ });
827
+ });
828
+
829
+ it('maintains stability after error recovery', async () => {
830
+ mockGetPermissionMap
831
+ .mockRejectedValueOnce(new Error('Error'))
832
+ .mockResolvedValue(mockPermissionMap);
833
+
834
+ const { result } = renderHook(() => usePermissions(mockUserId, mockScope));
835
+
836
+ await waitFor(() => {
837
+ expect(result.current.error).toBeDefined();
838
+ });
839
+
840
+ result.current.refetch();
841
+
842
+ await waitFor(() => {
843
+ expect(result.current.error).toBeNull();
844
+ expect(result.current.permissions).toEqual(mockPermissionMap);
845
+ });
846
+
847
+ // After recovery, operations should work normally
848
+ expect(result.current.hasPermission('read:users')).toBe(true);
849
+ });
850
+ });
851
+
852
+ describe('[integration] State Management', () => {
853
+ it('preserves state across hook re-renders', async () => {
854
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
855
+
856
+ const { result, rerender } = renderHook(() => usePermissions(mockUserId, mockScope));
857
+
858
+ await waitFor(() => {
859
+ expect(result.current.isLoading).toBe(false);
860
+ });
861
+
862
+ const firstPermissions = result.current.permissions;
863
+ rerender();
864
+ const secondPermissions = result.current.permissions;
865
+
866
+ expect(firstPermissions).toEqual(secondPermissions);
867
+ expect(result.current.hasPermission).toBe(result.current.hasPermission);
868
+ expect(result.current.refetch).toBe(result.current.refetch);
869
+ });
870
+
871
+ it('handles empty organization ID edge case', async () => {
872
+ const invalidScope = { organisationId: '', eventId: 'event-123' };
873
+
874
+ const { result } = renderHook(() => usePermissions(mockUserId, invalidScope as any));
875
+
876
+ await waitFor(() => {
877
+ expect(result.current.isLoading).toBeDefined();
878
+ });
879
+
880
+ expect(result.current.permissions).toEqual({});
881
+ });
882
+
883
+ it('handles null event ID', async () => {
884
+ const scopeWithNullEvent = { organisationId: 'org-123', eventId: null as any };
885
+
886
+ mockGetPermissionMap.mockResolvedValue(mockPermissionMap);
887
+
888
+ const { result } = renderHook(() => usePermissions(mockUserId, scopeWithNullEvent));
889
+
890
+ await waitFor(() => {
891
+ expect(result.current.isLoading).toBe(false);
892
+ });
893
+
894
+ expect(result.current.permissions).toEqual(mockPermissionMap);
895
+ });
896
+ });
601
897
  });
@@ -16,11 +16,15 @@ vi.mock('../../providers/UnifiedAuthProvider', () => ({
16
16
  useUnifiedAuth: vi.fn()
17
17
  }));
18
18
 
19
- vi.mock('../../providers/OrganisationProvider', () => ({
19
+ vi.mock('../../providers/services/UnifiedAuthProvider', () => ({
20
+ useUnifiedAuth: vi.fn()
21
+ }));
22
+
23
+ vi.mock('../../hooks/useOrganisations', () => ({
20
24
  useOrganisations: vi.fn()
21
25
  }));
22
26
 
23
- vi.mock('../../providers/EventProvider', () => ({
27
+ vi.mock('../../hooks/useEvents', () => ({
24
28
  useEvents: vi.fn()
25
29
  }));
26
30
 
@@ -30,9 +34,9 @@ const mockSupabaseClient = {
30
34
  };
31
35
 
32
36
  // Get the mocked functions
33
- import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
34
- import { useOrganisations } from '../../providers/OrganisationProvider';
35
- import { useEvents } from '../../providers/EventProvider';
37
+ import { useUnifiedAuth } from '../../providers';
38
+ import { useOrganisations } from '../../hooks/useOrganisations';
39
+ import { useEvents } from '../../hooks/useEvents';
36
40
 
37
41
  const mockUseUnifiedAuth = vi.mocked(useUnifiedAuth);
38
42
  const mockUseOrganisations = vi.mocked(useOrganisations);
@@ -67,9 +67,9 @@
67
67
  */
68
68
 
69
69
  import { useState, useEffect, useCallback, useMemo } from 'react';
70
- import { useUnifiedAuth } from '../../providers/UnifiedAuthProvider';
71
- import { useOrganisations } from '../../providers/OrganisationProvider';
72
- import { useEvents } from '../../providers/EventProvider';
70
+ import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
71
+ import { useOrganisations } from '../../hooks/useOrganisations';
72
+ import { useEvents } from '../../hooks/useEvents';
73
73
  import type {
74
74
  UserRBACContext,
75
75
  GlobalRole,
@@ -0,0 +1,232 @@
1
+ /**
2
+ * @file useResolvedScope Hook
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Hooks
5
+ * @since 1.0.0
6
+ *
7
+ * Shared hook for resolving RBAC scope from various contexts.
8
+ * This hook is used by both DataTable and PagePermissionGuard to ensure
9
+ * consistent scope resolution logic.
10
+ */
11
+
12
+ import { useEffect, useState, useRef } from 'react';
13
+ import { SupabaseClient } from '@supabase/supabase-js';
14
+ import type { Database } from '../../types/database';
15
+ import type { Scope } from '../types';
16
+ import { createScopeFromEvent } from '../utils/eventContext';
17
+ import { getCurrentAppName } from '../../utils/appNameResolver';
18
+
19
+ export interface UseResolvedScopeOptions {
20
+ /** Supabase client instance */
21
+ supabase: SupabaseClient<Database> | null;
22
+ /** Selected organisation ID */
23
+ selectedOrganisationId: string | null;
24
+ /** Selected event ID */
25
+ selectedEventId: string | null;
26
+ }
27
+
28
+ export interface UseResolvedScopeReturn {
29
+ /** Resolved scope, or null if not yet resolved */
30
+ resolvedScope: Scope | null;
31
+ /** Whether the scope resolution is in progress */
32
+ isLoading: boolean;
33
+ /** Error if scope resolution failed */
34
+ error: Error | null;
35
+ }
36
+
37
+ /**
38
+ * Resolves RBAC scope from organisation and event context
39
+ *
40
+ * This hook handles the complex logic of determining the correct RBAC scope
41
+ * based on available context (organisation, event, app). It ensures consistent
42
+ * scope resolution across the application.
43
+ *
44
+ * @param options - Hook options
45
+ * @returns Resolved scope and loading state
46
+ *
47
+ * @example
48
+ * ```tsx
49
+ * const { resolvedScope, isLoading } = useResolvedScope({
50
+ * supabase,
51
+ * selectedOrganisationId,
52
+ * selectedEventId
53
+ * });
54
+ *
55
+ * if (isLoading) return <Loading />;
56
+ * if (!resolvedScope) return <Error />;
57
+ *
58
+ * const permission = useCan(userId, resolvedScope, permission);
59
+ * ```
60
+ */
61
+ export function useResolvedScope({
62
+ supabase,
63
+ selectedOrganisationId,
64
+ selectedEventId
65
+ }: UseResolvedScopeOptions): UseResolvedScopeReturn {
66
+ const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);
67
+ const [isLoading, setIsLoading] = useState(true);
68
+ const [error, setError] = useState<Error | null>(null);
69
+
70
+ // Use a ref to track the stable scope and only update it when it actually changes
71
+ const stableScopeRef = useRef<{ organisationId: string; appId: string; eventId: string | undefined }>({
72
+ organisationId: '',
73
+ appId: '',
74
+ eventId: undefined
75
+ });
76
+
77
+ // Only update the stable scope if the resolved scope has actually changed
78
+ if (resolvedScope && resolvedScope.organisationId) {
79
+ const newScope = {
80
+ organisationId: resolvedScope.organisationId,
81
+ appId: resolvedScope.appId,
82
+ eventId: resolvedScope.eventId
83
+ };
84
+
85
+ // Only update if the scope has actually changed
86
+ if (stableScopeRef.current.organisationId !== newScope.organisationId ||
87
+ stableScopeRef.current.eventId !== newScope.eventId ||
88
+ stableScopeRef.current.appId !== newScope.appId) {
89
+ stableScopeRef.current = {
90
+ organisationId: newScope.organisationId,
91
+ appId: newScope.appId || '',
92
+ eventId: newScope.eventId
93
+ };
94
+ }
95
+ } else if (!resolvedScope) {
96
+ // Reset to empty scope when no resolved scope
97
+ stableScopeRef.current = { organisationId: '', appId: '', eventId: undefined };
98
+ }
99
+
100
+ const stableScope = stableScopeRef.current;
101
+
102
+ useEffect(() => {
103
+ let cancelled = false;
104
+
105
+ const resolveScope = async () => {
106
+ setIsLoading(true);
107
+ setError(null);
108
+
109
+ try {
110
+ // Get app ID from package.json or environment
111
+ let appId: string | undefined = undefined;
112
+
113
+ // Try to resolve from database
114
+ if (supabase) {
115
+ const appName = getCurrentAppName();
116
+ if (appName) {
117
+ try {
118
+ const { data: app, error } = await supabase
119
+ .from('rbac_apps')
120
+ .select('id, name, is_active')
121
+ .eq('name', appName)
122
+ .eq('is_active', true)
123
+ .single() as { data: { id: string; name: string; is_active: boolean } | null; error: any };
124
+
125
+ if (error) {
126
+ // Check if app exists but is inactive
127
+ const { data: inactiveApp } = await supabase
128
+ .from('rbac_apps')
129
+ .select('id, name, is_active')
130
+ .eq('name', appName)
131
+ .single() as { data: { id: string; name: string; is_active: boolean } | null };
132
+
133
+ if (inactiveApp) {
134
+ console.error(`[useResolvedScope] App "${appName}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
135
+ } else {
136
+ console.error(`[useResolvedScope] App "${appName}" not found in rbac_apps table`);
137
+ }
138
+ } else if (app) {
139
+ appId = app.id;
140
+ }
141
+ } catch (error) {
142
+ console.error('[useResolvedScope] Unexpected error resolving app ID:', error);
143
+ }
144
+ }
145
+ }
146
+
147
+ // If we have both organisation and event, use them directly
148
+ if (selectedOrganisationId && selectedEventId) {
149
+ if (!cancelled) {
150
+ setResolvedScope({
151
+ organisationId: selectedOrganisationId,
152
+ eventId: selectedEventId,
153
+ appId: appId
154
+ });
155
+ setIsLoading(false);
156
+ }
157
+ return;
158
+ }
159
+
160
+ // If we only have organisation, use it
161
+ if (selectedOrganisationId) {
162
+ if (!cancelled) {
163
+ setResolvedScope({
164
+ organisationId: selectedOrganisationId,
165
+ eventId: selectedEventId || undefined,
166
+ appId: appId
167
+ });
168
+ setIsLoading(false);
169
+ }
170
+ return;
171
+ }
172
+
173
+ // If we only have event, resolve organisation from event
174
+ if (selectedEventId && supabase) {
175
+ try {
176
+ const eventScope = await createScopeFromEvent(supabase, selectedEventId, appId);
177
+ if (!eventScope) {
178
+ console.error('[useResolvedScope] Could not resolve organization from event context');
179
+ if (!cancelled) {
180
+ setResolvedScope(null);
181
+ setError(new Error('Could not resolve organisation from event context'));
182
+ setIsLoading(false);
183
+ }
184
+ return;
185
+ }
186
+ // Preserve the resolved app ID
187
+ if (!cancelled) {
188
+ setResolvedScope({
189
+ ...eventScope,
190
+ appId: appId || eventScope.appId
191
+ });
192
+ setIsLoading(false);
193
+ }
194
+ } catch (err) {
195
+ console.error('[useResolvedScope] Error resolving scope from event:', err);
196
+ if (!cancelled) {
197
+ setResolvedScope(null);
198
+ setError(err as Error);
199
+ setIsLoading(false);
200
+ }
201
+ }
202
+ return;
203
+ }
204
+
205
+ // No context available
206
+ console.error('[useResolvedScope] No organisation or event context available');
207
+ if (!cancelled) {
208
+ setResolvedScope(null);
209
+ setError(new Error('No organisation or event context available'));
210
+ setIsLoading(false);
211
+ }
212
+ } catch (err) {
213
+ if (!cancelled) {
214
+ setError(err as Error);
215
+ setIsLoading(false);
216
+ }
217
+ }
218
+ };
219
+
220
+ resolveScope();
221
+
222
+ return () => {
223
+ cancelled = true;
224
+ };
225
+ }, [selectedOrganisationId, selectedEventId, supabase]);
226
+
227
+ return {
228
+ resolvedScope: stableScope.organisationId ? stableScope as Scope : null,
229
+ isLoading,
230
+ error
231
+ };
232
+ }