@jmruthers/pace-core 0.5.76 → 0.5.78

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 (447) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{RBACService-C4udt_Zp.d.ts → AuthService-Df3IozMG.d.ts} +10 -118
  3. package/dist/{DataTable-ntgmhO2W.d.ts → DataTable-BE0OXZKQ.d.ts} +9 -2
  4. package/dist/{DataTable-4GAVPIEG.js → DataTable-ETGVF4Y5.js} +50 -13
  5. package/dist/{PublicLoadingSpinner-BiNER8F5.d.ts → PublicLoadingSpinner-CnUaz0vG.d.ts} +5 -2
  6. package/dist/{UnifiedAuthProvider-Bj6YCf7c.d.ts → UnifiedAuthProvider-B391Aqum.d.ts} +42 -45
  7. package/dist/{UnifiedAuthProvider-3NKDOSOK.js → UnifiedAuthProvider-P5SOJAQ6.js} +4 -5
  8. package/dist/{api-DDMUKIUD.js → api-KG4A2X7P.js} +9 -3
  9. package/dist/{audit-6TOCAMKO.js → audit-65VNHEV2.js} +2 -2
  10. package/dist/{chunk-K34IM5CT.js → chunk-2OGV6IRV.js} +196 -626
  11. package/dist/chunk-2OGV6IRV.js.map +1 -0
  12. package/dist/{chunk-NTNILOBC.js → chunk-5BO3MI5Y.js} +4 -4
  13. package/dist/{chunk-XLZ7U46Z.js → chunk-CVMVPYAL.js} +9 -60
  14. package/dist/chunk-CVMVPYAL.js.map +1 -0
  15. package/dist/{chunk-URUTVZ7N.js → chunk-FL4ZCQLD.js} +2 -2
  16. package/dist/{chunk-LW7MMEAQ.js → chunk-FT2M4R4F.js} +2 -2
  17. package/dist/{chunk-5BSLGBYI.js → chunk-JCQZ6LA7.js} +2 -8
  18. package/dist/{chunk-5BSLGBYI.js.map → chunk-JCQZ6LA7.js.map} +1 -1
  19. package/dist/{chunk-KHJS6VIA.js → chunk-LRQ6RBJC.js} +157 -112
  20. package/dist/chunk-LRQ6RBJC.js.map +1 -0
  21. package/dist/{chunk-WN6XJWOS.js → chunk-MNJXXD6C.js} +274 -743
  22. package/dist/chunk-MNJXXD6C.js.map +1 -0
  23. package/dist/{chunk-KK73ZB4E.js → chunk-PTR5PMPE.js} +153 -132
  24. package/dist/chunk-PTR5PMPE.js.map +1 -0
  25. package/dist/{chunk-B2WTCLCV.js → chunk-Q7APDV6H.js} +18 -8
  26. package/dist/chunk-Q7APDV6H.js.map +1 -0
  27. package/dist/{chunk-A4FUBC7B.js → chunk-QGVSOUJ2.js} +2 -4
  28. package/dist/{chunk-A4FUBC7B.js.map → chunk-QGVSOUJ2.js.map} +1 -1
  29. package/dist/{chunk-FGMFQSHX.js → chunk-S63MFSY6.js} +500 -551
  30. package/dist/chunk-S63MFSY6.js.map +1 -0
  31. package/dist/{chunk-AFGTSUAD.js → chunk-VSOKOFRF.js} +4 -4
  32. package/dist/chunk-WUXCWRL6.js +20 -0
  33. package/dist/chunk-WUXCWRL6.js.map +1 -0
  34. package/dist/{chunk-Y6TXWPJO.js → chunk-YVVGHRGI.js} +105 -31
  35. package/dist/chunk-YVVGHRGI.js.map +1 -0
  36. package/dist/{chunk-M5IWZRBT.js → chunk-ZMNXIJP4.js} +2187 -981
  37. package/dist/chunk-ZMNXIJP4.js.map +1 -0
  38. package/dist/components.d.ts +6 -6
  39. package/dist/components.js +14 -18
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database-C3Szpi5J.d.ts → database-BXAfr2Y_.d.ts} +18 -0
  42. package/dist/hooks.d.ts +5 -5
  43. package/dist/hooks.js +8 -9
  44. package/dist/hooks.js.map +1 -1
  45. package/dist/index.d.ts +19 -27
  46. package/dist/index.js +21 -29
  47. package/dist/index.js.map +1 -1
  48. package/dist/{organisation-BtshODVF.d.ts → organisation-D6qRDtbF.d.ts} +1 -1
  49. package/dist/providers.d.ts +7 -21
  50. package/dist/providers.js +3 -10
  51. package/dist/rbac/index.d.ts +71 -221
  52. package/dist/rbac/index.js +15 -16
  53. package/dist/{types-CGX9Vyf5.d.ts → types-BDg1mAGG.d.ts} +36 -6
  54. package/dist/types.d.ts +3 -3
  55. package/dist/types.js +61 -18
  56. package/dist/types.js.map +1 -1
  57. package/dist/{unified-CM7T0aTK.d.ts → unified-DQ4VcT7H.d.ts} +1 -1
  58. package/dist/{usePublicRouteParams-B-CumWRc.d.ts → usePublicRouteParams-BlgwXweB.d.ts} +3 -3
  59. package/dist/utils.d.ts +2 -2
  60. package/dist/utils.js +52 -9
  61. package/dist/utils.js.map +1 -1
  62. package/docs/CONTENT_AUDIT_REPORT.md +253 -0
  63. package/docs/DOCUMENTATION_AUDIT.md +172 -0
  64. package/docs/README.md +142 -147
  65. package/docs/STYLE_GUIDE.md +37 -0
  66. package/docs/api/classes/ColumnFactory.md +17 -17
  67. package/docs/api/classes/ErrorBoundary.md +1 -1
  68. package/docs/api/classes/InvalidScopeError.md +4 -4
  69. package/docs/api/classes/MissingUserContextError.md +4 -4
  70. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  71. package/docs/api/classes/PermissionDeniedError.md +5 -5
  72. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  73. package/docs/api/classes/RBACAuditManager.md +8 -8
  74. package/docs/api/classes/RBACCache.md +35 -5
  75. package/docs/api/classes/RBACEngine.md +49 -20
  76. package/docs/api/classes/RBACError.md +4 -4
  77. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  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 +4 -4
  82. package/docs/api/interfaces/ButtonProps.md +1 -1
  83. package/docs/api/interfaces/CardProps.md +1 -1
  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/DataRecord.md +11 -0
  88. package/docs/api/interfaces/DataTableAction.md +65 -29
  89. package/docs/api/interfaces/DataTableColumn.md +36 -23
  90. package/docs/api/interfaces/DataTableProps.md +80 -38
  91. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  92. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  93. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  94. package/docs/api/interfaces/EventLogoProps.md +1 -1
  95. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  96. package/docs/api/interfaces/FileMetadata.md +1 -1
  97. package/docs/api/interfaces/FileReference.md +1 -1
  98. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  99. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  100. package/docs/api/interfaces/FileUploadProps.md +1 -1
  101. package/docs/api/interfaces/FooterProps.md +1 -1
  102. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  103. package/docs/api/interfaces/InputProps.md +1 -1
  104. package/docs/api/interfaces/LabelProps.md +1 -1
  105. package/docs/api/interfaces/LoginFormProps.md +1 -1
  106. package/docs/api/interfaces/NavigationAccessRecord.md +11 -11
  107. package/docs/api/interfaces/NavigationContextType.md +9 -9
  108. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  109. package/docs/api/interfaces/NavigationItem.md +1 -1
  110. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  111. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  112. package/docs/api/interfaces/Organisation.md +1 -1
  113. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  114. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  115. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  116. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  117. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  118. package/docs/api/interfaces/PaceLoginPageProps.md +16 -3
  119. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  120. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  121. package/docs/api/interfaces/PagePermissionGuardProps.md +2 -2
  122. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  123. package/docs/api/interfaces/PaletteData.md +1 -1
  124. package/docs/api/interfaces/PermissionEnforcerProps.md +4 -4
  125. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  126. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  127. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  128. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  129. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  130. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  131. package/docs/api/interfaces/RBACConfig.md +1 -1
  132. package/docs/api/interfaces/RBACLogger.md +1 -1
  133. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  134. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  135. package/docs/api/interfaces/RouteAccessRecord.md +2 -2
  136. package/docs/api/interfaces/RouteConfig.md +2 -2
  137. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  138. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  139. package/docs/api/interfaces/StorageConfig.md +1 -1
  140. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  141. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  142. package/docs/api/interfaces/StorageListOptions.md +1 -1
  143. package/docs/api/interfaces/StorageListResult.md +1 -1
  144. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  145. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  146. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  147. package/docs/api/interfaces/StyleImport.md +1 -1
  148. package/docs/api/interfaces/SwitchProps.md +1 -1
  149. package/docs/api/interfaces/ToastActionElement.md +1 -1
  150. package/docs/api/interfaces/ToastProps.md +1 -1
  151. package/docs/api/interfaces/UnifiedAuthContextType.md +94 -521
  152. package/docs/api/interfaces/UnifiedAuthProviderProps.md +16 -16
  153. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  154. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  155. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  156. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  157. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  158. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  159. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  160. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  161. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  162. package/docs/api/interfaces/UserEventAccess.md +11 -11
  163. package/docs/api/interfaces/UserMenuProps.md +1 -1
  164. package/docs/api/interfaces/UserProfile.md +1 -1
  165. package/docs/api/modules.md +251 -269
  166. package/docs/api-reference/components.md +193 -0
  167. package/docs/api-reference/hooks.md +265 -0
  168. package/docs/api-reference/providers.md +6 -0
  169. package/docs/api-reference/types.md +6 -0
  170. package/docs/api-reference/utilities.md +207 -0
  171. package/docs/architecture/README.md +6 -0
  172. package/docs/{database-schema-requirements.md → architecture/database-schema-requirements.md} +6 -0
  173. package/docs/architecture/rbac-security-architecture.md +258 -0
  174. package/docs/architecture/services.md +9 -1
  175. package/docs/best-practices/README.md +6 -0
  176. package/docs/best-practices/accessibility.md +6 -0
  177. package/docs/{common-patterns.md → best-practices/common-patterns.md} +6 -0
  178. package/docs/best-practices/deployment.md +6 -0
  179. package/docs/best-practices/performance.md +475 -2
  180. package/docs/best-practices/security.md +6 -0
  181. package/docs/best-practices/testing.md +6 -0
  182. package/docs/core-concepts/authentication.md +6 -0
  183. package/docs/core-concepts/events.md +6 -0
  184. package/docs/core-concepts/organisations.md +6 -0
  185. package/docs/core-concepts/permissions.md +6 -0
  186. package/docs/core-concepts/rbac-system.md +8 -0
  187. package/docs/documentation-index.md +121 -182
  188. package/docs/{consuming-app-vite-config.md → getting-started/consuming-app-vite-config.md} +6 -0
  189. package/docs/getting-started/documentation-index.md +40 -0
  190. package/docs/getting-started/examples/README.md +878 -35
  191. package/docs/{faq.md → getting-started/faq.md} +7 -1
  192. package/docs/getting-started/installation-guide.md +6 -0
  193. package/docs/{quick-reference.md → getting-started/quick-reference.md} +6 -0
  194. package/docs/implementation-guides/app-layout.md +6 -0
  195. package/docs/implementation-guides/authentication.md +1021 -0
  196. package/docs/implementation-guides/component-styling.md +6 -0
  197. package/docs/implementation-guides/data-tables.md +1264 -2076
  198. package/docs/implementation-guides/dynamic-colors.md +6 -0
  199. package/docs/implementation-guides/event-theming-summary.md +6 -0
  200. package/docs/{file-reference-system.md → implementation-guides/file-reference-system.md} +6 -0
  201. package/docs/implementation-guides/file-upload-storage.md +6 -0
  202. package/docs/implementation-guides/forms.md +6 -0
  203. package/docs/implementation-guides/inactivity-tracking.md +6 -0
  204. package/docs/implementation-guides/navigation.md +6 -0
  205. package/docs/implementation-guides/organisation-security.md +6 -0
  206. package/docs/implementation-guides/permission-enforcement.md +6 -0
  207. package/docs/implementation-guides/public-pages-advanced.md +6 -0
  208. package/docs/implementation-guides/public-pages.md +6 -0
  209. package/docs/migration/MIGRATION_GUIDE.md +827 -351
  210. package/docs/migration/README.md +7 -1
  211. package/docs/migration/organisation-context-timing-fix.md +6 -0
  212. package/docs/migration/rbac-migration.md +44 -1
  213. package/docs/migration/service-architecture.md +6 -0
  214. package/docs/migration/v0.4.15-tailwind-scanning.md +6 -0
  215. package/docs/migration/v0.4.16-css-first-approach.md +6 -0
  216. package/docs/migration/v0.4.17-source-path-fix.md +6 -0
  217. package/docs/rbac/README-rbac-rls-integration.md +6 -0
  218. package/docs/rbac/README.md +6 -0
  219. package/docs/rbac/advanced-patterns.md +6 -0
  220. package/docs/rbac/api-reference.md +7 -1
  221. package/docs/rbac/breaking-changes-v3.md +222 -0
  222. package/docs/rbac/examples/rbac-rls-integration-example.md +6 -0
  223. package/docs/rbac/examples.md +6 -0
  224. package/docs/rbac/getting-started.md +6 -0
  225. package/docs/rbac/migration-guide.md +260 -0
  226. package/docs/rbac/quick-start.md +70 -13
  227. package/docs/rbac/rbac-rls-integration.md +6 -0
  228. package/docs/rbac/super-admin-guide.md +6 -0
  229. package/docs/rbac/troubleshooting.md +6 -0
  230. package/docs/security/README.md +6 -0
  231. package/docs/security/checklist.md +6 -0
  232. package/docs/styles/README.md +7 -1
  233. package/docs/{usage.md → styles/usage.md} +6 -0
  234. package/docs/testing/README.md +6 -0
  235. package/docs/{visual-testing.md → testing/visual-testing.md} +6 -0
  236. package/docs/troubleshooting/README.md +387 -5
  237. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +6 -0
  238. package/docs/troubleshooting/common-issues.md +6 -0
  239. package/docs/troubleshooting/database-view-compatibility.md +6 -0
  240. package/docs/troubleshooting/organisation-context-setup.md +6 -0
  241. package/docs/troubleshooting/react-hooks-issue-analysis.md +6 -0
  242. package/docs/troubleshooting/styling-issues.md +6 -0
  243. package/docs/troubleshooting/tailwind-content-scanning.md +6 -0
  244. package/package.json +1 -1
  245. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -1
  246. package/src/__tests__/helpers/test-providers.tsx +3 -53
  247. package/src/components/DataTable/DataTable.test.tsx +319 -0
  248. package/src/components/DataTable/DataTable.tsx +32 -11
  249. package/src/components/DataTable/__tests__/{DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx.skip} +6 -4
  250. package/src/components/DataTable/__tests__/{DataTable.test.tsx → DataTable.test.tsx.skip} +6 -4
  251. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +31 -9
  252. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +601 -0
  253. package/src/components/DataTable/__tests__/keyboard.test.tsx +615 -0
  254. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +639 -0
  255. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx.skip +330 -0
  256. package/src/components/DataTable/components/AccessDeniedPage.tsx +2 -2
  257. package/src/components/DataTable/components/ActionButtons.tsx +88 -104
  258. package/src/components/DataTable/components/DataTableCore.tsx +309 -337
  259. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +4 -2
  260. package/src/components/DataTable/components/DataTableModals.tsx +22 -1
  261. package/src/components/DataTable/components/EditableRow.tsx +69 -84
  262. package/src/components/DataTable/components/EmptyState.tsx +5 -1
  263. package/src/components/DataTable/components/ImportModal.tsx +65 -36
  264. package/src/components/DataTable/components/PaginationControls.tsx +40 -100
  265. package/src/components/DataTable/components/UnifiedTableBody.tsx +125 -148
  266. package/src/components/DataTable/context/DataTableContext.tsx +1 -1
  267. package/src/components/DataTable/core/ColumnFactory.ts +5 -0
  268. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +12 -10
  269. package/src/components/DataTable/examples/HierarchicalExample.tsx +1 -1
  270. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +1 -0
  271. package/src/components/DataTable/examples/PerformanceExample.tsx +1 -0
  272. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +1 -5
  273. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +167 -0
  274. package/src/components/DataTable/hooks/index.ts +7 -0
  275. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +32 -15
  276. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +102 -0
  277. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +89 -0
  278. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +117 -0
  279. package/src/components/DataTable/hooks/useDataTablePermissions.ts +71 -27
  280. package/src/components/DataTable/hooks/useDataTableState.ts +39 -11
  281. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +33 -0
  282. package/src/components/DataTable/hooks/useHierarchicalState.ts +15 -1
  283. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +447 -0
  284. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +94 -0
  285. package/src/components/DataTable/hooks/useTableColumns.ts +10 -7
  286. package/src/components/DataTable/hooks/useTableHandlers.ts +174 -0
  287. package/src/components/DataTable/index.ts +12 -3
  288. package/src/components/DataTable/types.ts +129 -9
  289. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +159 -22
  290. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +111 -0
  291. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +15 -29
  292. package/src/components/DataTable/utils/a11yUtils.ts +244 -0
  293. package/src/components/DataTable/utils/debugTools.ts +609 -0
  294. package/src/components/DataTable/utils/exportUtils.ts +114 -16
  295. package/src/components/DataTable/utils/flexibleImport.ts +202 -32
  296. package/src/components/DataTable/utils/hierarchicalUtils.ts +1 -1
  297. package/src/components/DataTable/utils/index.ts +2 -0
  298. package/src/components/DataTable/utils/paginationUtils.ts +350 -0
  299. package/src/components/DataTable/utils/rowUtils.ts +6 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -24
  301. package/src/components/NavigationMenu/NavigationMenu.tsx +19 -8
  302. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +1 -23
  303. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +56 -6
  304. package/src/components/PaceLoginPage/PaceLoginPage.tsx +137 -13
  305. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +1 -1
  306. package/src/components/Select/Select.tsx +1 -0
  307. package/src/components/examples/PermissionExample.tsx +173 -0
  308. package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
  309. package/src/examples/PublicEventPage.tsx +274 -0
  310. package/src/examples/PublicPageApp.tsx +308 -0
  311. package/src/examples/PublicPageUsageExample.tsx +216 -0
  312. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +12 -1
  313. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +129 -17
  314. package/src/hooks/__tests__/useRBAC.unit.test.ts +151 -846
  315. package/src/hooks/useOrganisationPermissions.test.ts +42 -18
  316. package/src/hooks/useOrganisationPermissions.ts +12 -6
  317. package/src/hooks/useOrganisationSecurity.test.ts +138 -85
  318. package/src/hooks/useOrganisationSecurity.ts +41 -10
  319. package/src/index.ts +0 -1
  320. package/src/providers/AuthProvider.simplified.tsx +880 -0
  321. package/src/providers/UnifiedAuthProvider.test.simple.tsx +8 -8
  322. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +29 -19
  323. package/src/providers/index.ts +0 -1
  324. package/src/providers/services/EventServiceProvider.tsx +19 -15
  325. package/src/providers/services/InactivityServiceProvider.tsx +19 -15
  326. package/src/providers/services/OrganisationServiceProvider.tsx +19 -15
  327. package/src/providers/services/UnifiedAuthProvider.tsx +156 -127
  328. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +1 -1
  329. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -3
  330. package/src/rbac/README.md +1 -1
  331. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +25 -27
  332. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +313 -0
  333. package/src/rbac/__tests__/engine.comprehensive.test.ts +114 -348
  334. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +28 -110
  335. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +33 -85
  336. package/src/rbac/__tests__/scenarios.user-role.test.tsx +2 -2
  337. package/src/rbac/adapters.tsx +26 -69
  338. package/src/rbac/api.test.ts +90 -27
  339. package/src/rbac/api.ts +61 -10
  340. package/src/rbac/audit.test.ts +33 -38
  341. package/src/rbac/audit.ts +21 -6
  342. package/src/rbac/cache.ts +33 -1
  343. package/src/rbac/components/NavigationGuard.tsx +11 -11
  344. package/src/rbac/components/NavigationProvider.test.tsx +11 -5
  345. package/src/rbac/components/NavigationProvider.tsx +37 -13
  346. package/src/rbac/components/PagePermissionGuard.tsx +111 -50
  347. package/src/rbac/components/PagePermissionProvider.tsx +5 -5
  348. package/src/rbac/components/PermissionEnforcer.tsx +11 -11
  349. package/src/rbac/components/RoleBasedRouter.tsx +5 -5
  350. package/src/rbac/components/SecureDataProvider.tsx +5 -5
  351. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +8 -8
  352. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +14 -14
  353. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +12 -12
  354. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +6 -6
  355. package/src/rbac/engine.test.simple.ts +19 -13
  356. package/src/rbac/engine.test.ts +1 -0
  357. package/src/rbac/engine.ts +330 -766
  358. package/src/rbac/errors.ts +156 -0
  359. package/src/rbac/hooks/usePermissions.ts +32 -10
  360. package/src/rbac/hooks/useRBAC.test.ts +126 -512
  361. package/src/rbac/hooks/useRBAC.ts +147 -193
  362. package/src/rbac/hooks/useResolvedScope.ts +12 -0
  363. package/src/rbac/index.ts +7 -4
  364. package/src/rbac/security.ts +109 -18
  365. package/src/rbac/types.ts +12 -1
  366. package/src/services/AuthService.ts +2 -15
  367. package/src/services/EventService.ts +43 -46
  368. package/src/services/OrganisationService.ts +51 -31
  369. package/src/services/__tests__/AuthService.test.ts +1 -1
  370. package/src/services/__tests__/EventService.test.ts +1 -1
  371. package/src/services/__tests__/OrganisationService.test.ts +1 -1
  372. package/src/services/base/BaseService.ts +8 -0
  373. package/src/styles/base.css +208 -0
  374. package/src/styles/semantic.css +24 -0
  375. package/src/types/database.generated.ts +7347 -0
  376. package/src/types/database.ts +20 -0
  377. package/src/utils/logger.ts +179 -0
  378. package/src/utils/organisationContext.ts +11 -4
  379. package/src/utils/storage/__tests__/helpers.unit.test.ts +6 -2
  380. package/dist/appNameResolver-UURKN7NF.js +0 -22
  381. package/dist/audit-6TOCAMKO.js.map +0 -1
  382. package/dist/chunk-B2WTCLCV.js.map +0 -1
  383. package/dist/chunk-FGMFQSHX.js.map +0 -1
  384. package/dist/chunk-K34IM5CT.js.map +0 -1
  385. package/dist/chunk-KHJS6VIA.js.map +0 -1
  386. package/dist/chunk-KK73ZB4E.js.map +0 -1
  387. package/dist/chunk-M5IWZRBT.js.map +0 -1
  388. package/dist/chunk-ULBI5JGB.js +0 -109
  389. package/dist/chunk-ULBI5JGB.js.map +0 -1
  390. package/dist/chunk-WN6XJWOS.js.map +0 -1
  391. package/dist/chunk-XLZ7U46Z.js.map +0 -1
  392. package/dist/chunk-Y6TXWPJO.js.map +0 -1
  393. package/docs/DOCUMENTATION_CHECKLIST.md +0 -281
  394. package/docs/TERMINOLOGY.md +0 -231
  395. package/docs/api/interfaces/RBACContextType.md +0 -468
  396. package/docs/api/interfaces/RBACProviderProps.md +0 -107
  397. package/docs/best-practices/performance-expansion.md +0 -473
  398. package/docs/breaking-changes.md +0 -179
  399. package/docs/consuming-app-example.md +0 -290
  400. package/docs/documentation-templates.md +0 -539
  401. package/docs/examples/navigation-menu-auth-fix.md +0 -344
  402. package/docs/getting-started/examples/basic-auth-app.md +0 -520
  403. package/docs/getting-started/examples/full-featured-app.md +0 -616
  404. package/docs/getting-started/quick-start.md +0 -376
  405. package/docs/implementation-guides/datatable-filtering.md +0 -313
  406. package/docs/implementation-guides/datatable-rbac-usage.md +0 -317
  407. package/docs/implementation-guides/hierarchical-datatable.md +0 -850
  408. package/docs/implementation-guides/large-datasets.md +0 -281
  409. package/docs/implementation-guides/performance.md +0 -403
  410. package/docs/migration/quick-migration-guide.md +0 -320
  411. package/docs/migration-guide.md +0 -193
  412. package/docs/migration-guides/unified-auth-provider-mandatory-timeouts.md +0 -226
  413. package/docs/performance/README.md +0 -551
  414. package/docs/style-guide.md +0 -964
  415. package/docs/troubleshooting/authentication-issues.md +0 -334
  416. package/docs/troubleshooting/debugging.md +0 -1117
  417. package/docs/troubleshooting/migration.md +0 -918
  418. package/src/__tests__/hooks/usePermissions.test.ts +0 -261
  419. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.rbac.test.tsx +0 -574
  420. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -613
  421. package/src/hooks/services/__tests__/useServiceHooks.test.tsx +0 -137
  422. package/src/hooks/services/usePermissions.ts +0 -70
  423. package/src/hooks/services/useRBACService.ts +0 -30
  424. package/src/hooks/usePermissionCheck.ts +0 -150
  425. package/src/providers/__tests__/ServiceProviders.test.tsx +0 -477
  426. package/src/providers/services/RBACServiceProvider.tsx +0 -79
  427. package/src/rbac/__tests__/integration.authflow.test.tsx +0 -119
  428. package/src/rbac/__tests__/integration.navigation.test.tsx +0 -69
  429. package/src/rbac/__tests__/integration.securedata.test.tsx +0 -92
  430. package/src/rbac/__tests__/integration.smoke.test.tsx +0 -73
  431. package/src/rbac/providers/RBACProvider.tsx +0 -645
  432. package/src/rbac/providers/__tests__/RBACProvider.integration.test.tsx +0 -688
  433. package/src/rbac/providers/__tests__/RBACProvider.test.tsx +0 -1186
  434. package/src/rbac/providers/index.ts +0 -11
  435. package/src/services/RBACService.ts +0 -522
  436. package/src/services/__tests__/RBACService.test.ts +0 -492
  437. package/src/services/interfaces/IRBACService.ts +0 -62
  438. package/src/utils/appNameResolver.test 2.ts +0 -494
  439. /package/dist/{DataTable-4GAVPIEG.js.map → DataTable-ETGVF4Y5.js.map} +0 -0
  440. /package/dist/{UnifiedAuthProvider-3NKDOSOK.js.map → UnifiedAuthProvider-P5SOJAQ6.js.map} +0 -0
  441. /package/dist/{api-DDMUKIUD.js.map → api-KG4A2X7P.js.map} +0 -0
  442. /package/dist/{appNameResolver-UURKN7NF.js.map → audit-65VNHEV2.js.map} +0 -0
  443. /package/dist/{chunk-NTNILOBC.js.map → chunk-5BO3MI5Y.js.map} +0 -0
  444. /package/dist/{chunk-URUTVZ7N.js.map → chunk-FL4ZCQLD.js.map} +0 -0
  445. /package/dist/{chunk-LW7MMEAQ.js.map → chunk-FT2M4R4F.js.map} +0 -0
  446. /package/dist/{chunk-AFGTSUAD.js.map → chunk-VSOKOFRF.js.map} +0 -0
  447. /package/docs/{app.css.example → styles/app.css.example} +0 -0
package/src/rbac/types.ts CHANGED
@@ -40,7 +40,7 @@ export type PermissionCheck = {
40
40
  pageId?: UUID | string;
41
41
  };
42
42
 
43
- export type PermissionMap = Record<string /* pageId */, Operation[]>;
43
+ export type PermissionMap = Record<Permission, boolean> & Partial<Record<'*', boolean>>;
44
44
 
45
45
  // ============================================================================
46
46
  // ROLE TYPES
@@ -162,6 +162,17 @@ export interface RBACAuditEvent {
162
162
  created_at: string;
163
163
  }
164
164
 
165
+ export interface RBACAppContext {
166
+ appId: UUID;
167
+ hasAccess: boolean;
168
+ }
169
+
170
+ export interface RBACRoleContext {
171
+ globalRole: GlobalRole | null;
172
+ organisationRole: OrganisationRole | null;
173
+ eventAppRole: EventAppRole | null;
174
+ }
175
+
165
176
  // ============================================================================
166
177
  // CACHE TYPES
167
178
  // ============================================================================
@@ -11,12 +11,11 @@
11
11
  import { type SupabaseClient, type User, type Session, AuthError } from '@supabase/supabase-js';
12
12
  import { BaseService } from './base/BaseService';
13
13
  import { IAuthService, AuthResult } from './interfaces/IAuthService';
14
- import { DebugLogger } from '../utils/debugLogger';
15
14
 
16
15
  export class AuthService extends BaseService implements IAuthService {
17
16
  private user: User | null = null;
18
17
  private session: Session | null = null;
19
- private authLoading = true;
18
+ private authLoading = false;
20
19
  private authError: AuthError | null = null;
21
20
  private supabaseClient: SupabaseClient | null = null;
22
21
  private authStateSubscription: any = null;
@@ -307,16 +306,12 @@ export class AuthService extends BaseService implements IAuthService {
307
306
  this.authStateSubscription = this.supabaseClient.auth.onAuthStateChange(
308
307
  (event, session) => {
309
308
  try {
310
- DebugLogger.log('AuthService', 'Auth state changed:', event, session?.user?.email);
311
-
312
309
  // Handle different auth events
313
310
  if (event === 'SIGNED_OUT') {
314
- DebugLogger.log('AuthService', 'User signed out, clearing all state');
315
311
  this.session = null;
316
312
  this.user = null;
317
313
  this.authError = null;
318
314
  } else if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {
319
- DebugLogger.log('AuthService', 'User signed in or token refreshed');
320
315
  this.session = session;
321
316
  this.user = session?.user ?? null;
322
317
 
@@ -325,7 +320,6 @@ export class AuthService extends BaseService implements IAuthService {
325
320
  this.authError = null;
326
321
  }
327
322
  } else if (event === 'INITIAL_SESSION') {
328
- DebugLogger.log('AuthService', 'Initial session event');
329
323
  if (session) {
330
324
  this.session = session;
331
325
  this.user = session.user ?? null;
@@ -357,8 +351,6 @@ export class AuthService extends BaseService implements IAuthService {
357
351
  }
358
352
 
359
353
  try {
360
- DebugLogger.log('AuthService', 'Initializing authentication...');
361
-
362
354
  // First, try to get the current session
363
355
  const { data: { session: currentSession }, error: sessionError } = await this.supabaseClient.auth.getSession();
364
356
 
@@ -368,19 +360,14 @@ export class AuthService extends BaseService implements IAuthService {
368
360
  }
369
361
 
370
362
  if (currentSession) {
371
- DebugLogger.log('AuthService', 'Session restored from storage:', currentSession.user?.email);
372
363
  this.session = currentSession;
373
364
  this.user = currentSession.user;
374
365
  this.authError = null;
375
366
  } else {
376
- DebugLogger.log('AuthService', 'No session found in storage');
377
367
  // Try to get user anyway (in case session is expired but user exists)
378
368
  const { data: { user: currentUser }, error: userError } = await this.supabaseClient.auth.getUser();
379
369
 
380
- if (userError) {
381
- DebugLogger.log('AuthService', 'No user found:', userError.message);
382
- } else if (currentUser) {
383
- DebugLogger.log('AuthService', 'User found without session:', currentUser.email);
370
+ if (!userError && currentUser) {
384
371
  this.user = currentUser;
385
372
  // Don't set session if it's null - this prevents issues
386
373
  }
@@ -8,23 +8,25 @@
8
8
  * Handles event management and selection with organisation context validation.
9
9
  */
10
10
 
11
+ import { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';
11
12
  import { BaseService } from './base/BaseService';
12
13
  import { IEventService } from './interfaces/IEventService';
13
14
  import { Event } from '../types/unified';
15
+ import { Organisation } from '../types/organisation';
14
16
  import { DebugLogger } from '../utils/debugLogger';
15
17
 
16
18
  export class EventService extends BaseService implements IEventService {
17
19
  private events: Event[] = [];
18
20
  private selectedEvent: Event | null = null;
19
- private _isLoading = true;
21
+ private _isLoading = false; // Start as false to avoid blocking UI
20
22
  private error: Error | null = null;
21
23
 
22
24
  // Dependencies
23
- private supabaseClient: any = null;
24
- private user: any = null;
25
- private session: any = null;
25
+ private supabaseClient: SupabaseClient | null = null;
26
+ private user: User | null = null;
27
+ private session: Session | null = null;
26
28
  private appName: string = '';
27
- private selectedOrganisation: any = null;
29
+ private selectedOrganisation: Organisation | null = null;
28
30
  private setSelectedEventId: ((eventId: string | null) => void) | null = null;
29
31
 
30
32
  // Internal state management
@@ -34,11 +36,11 @@ export class EventService extends BaseService implements IEventService {
34
36
  private userClearedEventRef = false;
35
37
 
36
38
  constructor(
37
- supabaseClient: any,
38
- user: any,
39
- session: any,
39
+ supabaseClient: SupabaseClient,
40
+ user: User | null,
41
+ session: Session | null,
40
42
  appName: string,
41
- selectedOrganisation: any,
43
+ selectedOrganisation: Organisation | null,
42
44
  setSelectedEventId: (eventId: string | null) => void
43
45
  ) {
44
46
  super();
@@ -52,19 +54,36 @@ export class EventService extends BaseService implements IEventService {
52
54
 
53
55
  // Update dependencies
54
56
  updateDependencies(
55
- supabaseClient: any,
56
- user: any,
57
- session: any,
57
+ supabaseClient: SupabaseClient,
58
+ user: User | null,
59
+ session: Session | null,
58
60
  appName: string,
59
- selectedOrganisation: any,
61
+ selectedOrganisation: Organisation | null,
60
62
  setSelectedEventId: (eventId: string | null) => void
61
63
  ): void {
64
+ const previousOrgId = this.selectedOrganisation?.id;
65
+ const newOrgId = selectedOrganisation?.id;
66
+
62
67
  this.supabaseClient = supabaseClient;
63
68
  this.user = user;
64
69
  this.session = session;
65
70
  this.appName = appName;
66
71
  this.selectedOrganisation = selectedOrganisation;
67
72
  this.setSelectedEventId = setSelectedEventId;
73
+
74
+ // If organisation changed (from null to value, or different org), reset initialization
75
+ // This ensures events are re-fetched when organisation context becomes available
76
+ if (previousOrgId !== newOrgId) {
77
+ this.resetInitialization(); // Reset BaseService's isInitialized flag
78
+ this.isInitializedRef = false;
79
+ this.isFetchingRef = false;
80
+ // Clear events when switching organisations
81
+ if (previousOrgId !== null && newOrgId !== previousOrgId) {
82
+ this.events = [];
83
+ this.selectedEvent = null;
84
+ }
85
+ }
86
+
68
87
  this.notify();
69
88
  }
70
89
 
@@ -153,14 +172,12 @@ export class EventService extends BaseService implements IEventService {
153
172
 
154
173
  if (persistedEventId && events.length > 0) {
155
174
  const persistedEvent = events.find(event => event.event_id === persistedEventId);
156
- if (persistedEvent) {
157
- DebugLogger.log('EventService', 'Restoring persisted event:', persistedEvent.event_name);
158
- this.selectedEvent = persistedEvent;
159
- this.setSelectedEventId?.(persistedEventId);
160
- return true;
161
- } else {
162
- DebugLogger.log('EventService', 'Persisted event not found in current events, clearing storage');
163
- // Clear invalid persisted event
175
+ if (persistedEvent) {
176
+ this.selectedEvent = persistedEvent;
177
+ this.setSelectedEventId?.(persistedEventId);
178
+ return true;
179
+ } else {
180
+ // Clear invalid persisted event
164
181
  sessionStorage.removeItem('pace-core-selected-event');
165
182
  localStorage.removeItem('pace-core-selected-event');
166
183
  }
@@ -198,7 +215,6 @@ export class EventService extends BaseService implements IEventService {
198
215
  autoSelectNextEvent(events: Event[]): void {
199
216
  const nextEvent = this.getNextEventByDate(events);
200
217
  if (nextEvent) {
201
- DebugLogger.log('EventService', 'Auto-selecting next event:', nextEvent.event_name);
202
218
  this.selectedEvent = nextEvent;
203
219
  this.setSelectedEventId?.(nextEvent.event_id);
204
220
  this.persistEventSelection(nextEvent.event_id);
@@ -226,49 +242,31 @@ export class EventService extends BaseService implements IEventService {
226
242
 
227
243
  private async fetchEvents(): Promise<void> {
228
244
  if (!this.user || !this.session || !this.supabaseClient || !this.appName || !this.selectedOrganisation) {
229
- DebugLogger.log('EventService', 'Missing required dependencies, skipping fetch');
230
- this._isLoading = false;
245
+ // Already false from initialization, just notify
231
246
  this.notify();
232
247
  return;
233
248
  }
249
+
250
+ // Only set loading to true if we actually have dependencies and are going to fetch
251
+ this._isLoading = true;
252
+ this.notify();
234
253
 
235
254
  // Prevent multiple simultaneous fetches
236
255
  if (this.isFetchingRef) {
237
- DebugLogger.log('EventService', 'Already fetching events, skipping');
238
256
  return;
239
257
  }
240
258
 
241
- DebugLogger.log('EventService', 'User and organisation found, fetching events for:', {
242
- userId: this.user.id,
243
- appName: this.appName,
244
- organisationId: this.selectedOrganisation.id,
245
- organisationName: this.selectedOrganisation.display_name
246
- });
247
-
248
259
  this.isFetchingRef = true;
249
260
  let isMounted = true;
250
261
 
251
262
  try {
252
263
  // Call the RPC function following the established pattern
253
- DebugLogger.log('EventService', 'Calling data_user_events_get RPC with:', {
254
- user_id: this.user.id,
255
- organisation_id: this.selectedOrganisation.id,
256
- app_name: this.appName
257
- });
258
-
259
264
  const { data, error: rpcError } = await this.supabaseClient.rpc('data_user_events_get', {
260
265
  p_user_id: this.user.id,
261
266
  p_organisation_id: this.selectedOrganisation.id,
262
267
  p_app_name: this.appName
263
268
  });
264
269
 
265
- DebugLogger.log('EventService', 'RPC response:', {
266
- data,
267
- error: rpcError,
268
- dataLength: data?.length || 0,
269
- organisationId: this.selectedOrganisation.id
270
- });
271
-
272
270
  if (rpcError) {
273
271
  throw new Error(rpcError.message || 'Failed to fetch events');
274
272
  }
@@ -312,7 +310,6 @@ export class EventService extends BaseService implements IEventService {
312
310
  if (!persistedEventLoaded && !this.userClearedEventRef) {
313
311
  const nextEvent = this.getNextEventByDate(transformedEvents);
314
312
  if (nextEvent) {
315
- DebugLogger.log('EventService', 'Auto-selecting next event after no persisted event found:', nextEvent.event_name);
316
313
  this.hasAutoSelectedRef = true;
317
314
  this.selectedEvent = nextEvent;
318
315
  this.setSelectedEventId?.(nextEvent.event_id);
@@ -18,14 +18,13 @@ import type {
18
18
  OrganisationHierarchy
19
19
  } from '../types/organisation';
20
20
  import { setOrganisationContext } from '../utils/organisationContext';
21
- import { DebugLogger } from '../utils/debugLogger';
22
21
 
23
22
  export class OrganisationService extends BaseService implements IOrganisationService {
24
23
  private _selectedOrganisation: Organisation | null = null;
25
24
  private _organisations: Organisation[] = [];
26
25
  private _userMemberships: OrganisationMembership[] = [];
27
26
  private _roleMapState: Map<string, string> = new Map();
28
- private _isLoading = true;
27
+ private _isLoading = false;
29
28
  private _error: Error | null = null;
30
29
  private _isContextReady = false;
31
30
  private retryCount = 0;
@@ -52,7 +51,9 @@ export class OrganisationService extends BaseService implements IOrganisationSer
52
51
  getSelectedOrganisation(): Organisation | null { return this._selectedOrganisation; }
53
52
  getOrganisations(): Organisation[] { return this._organisations; }
54
53
  getUserMemberships(): OrganisationMembership[] { return this._userMemberships; }
55
- isLoading(): boolean { return this._isLoading; }
54
+ isLoading(): boolean {
55
+ return this._isLoading;
56
+ }
56
57
  getError(): Error | null { return this._error; }
57
58
  hasValidOrganisationContext(): boolean { return !!(this._selectedOrganisation && !this._isLoading && !this._error && this._isContextReady); }
58
59
  isContextReady(): boolean { return this._isContextReady; }
@@ -101,15 +102,23 @@ export class OrganisationService extends BaseService implements IOrganisationSer
101
102
 
102
103
  // Update dependencies
103
104
  updateDependencies(user: User | null, session: Session | null): void {
105
+ const wasAuthenticated = !!(this.user && this.session);
106
+ const isAuthenticated = !!(user && session);
107
+
104
108
  this.user = user;
105
109
  this.session = session;
110
+
111
+ // If user logs out, allow re-initialization when they log back in
112
+ if (wasAuthenticated && !isAuthenticated) {
113
+ // Reset BaseService initialization state to allow re-initialization
114
+ (this as any).isInitialized = false;
115
+ }
116
+
106
117
  this.notify();
107
118
  }
108
119
 
109
120
  // Organisation methods
110
121
  async switchOrganisation(orgId: string): Promise<void> {
111
- DebugLogger.log("OrganisationService", "Switching to organisation:", orgId);
112
-
113
122
  // Validate access
114
123
  if (!this.validateOrganisationAccess(orgId)) {
115
124
  throw new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;
@@ -128,7 +137,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
128
137
  // Set database organisation context
129
138
  await this.setDatabaseOrganisationContext(targetOrg);
130
139
 
131
- DebugLogger.log("OrganisationService", "Switched to organisation:", targetOrg.display_name);
132
140
  this.notify();
133
141
  }
134
142
 
@@ -206,7 +214,11 @@ export class OrganisationService extends BaseService implements IOrganisationSer
206
214
  // Lifecycle methods
207
215
  async initialize(): Promise<void> {
208
216
  await super.initialize();
209
- await this.loadUserOrganisations();
217
+
218
+ // Don't load if already loading (prevents duplicate loads during rapid auth events)
219
+ if (!this.isLoadingRef) {
220
+ await this.loadUserOrganisations();
221
+ }
210
222
  }
211
223
 
212
224
  cleanup(): void {
@@ -214,9 +226,11 @@ export class OrganisationService extends BaseService implements IOrganisationSer
214
226
  this.isLoadingRef = false;
215
227
  this.hasFailedRef = false;
216
228
  this.lastLoadTimeRef = 0;
217
- // Abort any pending requests
229
+ // Don't abort pending requests - let them complete naturally
230
+ // Aborting causes React StrictMode issues where requests are cancelled mid-flight
231
+ // The requests will complete on their own and update state if needed
218
232
  if (this.abortControllerRef) {
219
- this.abortControllerRef.abort();
233
+ // Clear the reference but don't abort - let requests complete
220
234
  this.abortControllerRef = null;
221
235
  }
222
236
  // Reset state
@@ -247,13 +261,25 @@ export class OrganisationService extends BaseService implements IOrganisationSer
247
261
  }
248
262
 
249
263
  try {
250
- await setOrganisationContext(this.supabaseClient, organisation.id);
251
- DebugLogger.log('OrganisationService', 'Database organisation context set to:', organisation.display_name);
264
+ console.log('[OrganisationService] Setting database organisation context for:', organisation.id);
265
+
266
+ // Add timeout to prevent hanging
267
+ const timeoutPromise = new Promise((_, reject) => {
268
+ setTimeout(() => reject(new Error('Context setting timeout after 5 seconds')), 5000);
269
+ });
270
+
271
+ const contextPromise = setOrganisationContext(this.supabaseClient, organisation.id);
272
+
273
+ await Promise.race([contextPromise, timeoutPromise]);
274
+
275
+ console.log('[OrganisationService] Database organisation context set successfully');
252
276
  this._isContextReady = true;
253
277
  this.notify();
254
278
  } catch (error) {
255
279
  console.error('[OrganisationService] Failed to set database organisation context:', error);
256
- this._isContextReady = false;
280
+ // Set context ready to true anyway - this is a non-critical operation
281
+ // The app should still work without database context
282
+ this._isContextReady = true;
257
283
  this.notify();
258
284
  // Don't throw - this is a non-critical operation
259
285
  }
@@ -266,7 +292,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
266
292
 
267
293
  if (!this.user || !this.session || !this.supabaseClient) {
268
294
  // Clear state when no user, session, or supabase client
269
- DebugLogger.log('OrganisationService', 'Clearing organisation state - no user, session, or supabase client');
270
295
  this._selectedOrganisation = null;
271
296
  this._organisations = [];
272
297
  this._userMemberships = [];
@@ -279,6 +304,9 @@ export class OrganisationService extends BaseService implements IOrganisationSer
279
304
  // Additional check to prevent loading during auth state changes
280
305
  if (this.isLoadingRef) {
281
306
  console.log("OrganisationService", "Already loading, skipping duplicate load");
307
+ // Ensure loading state is correct
308
+ this._isLoading = true;
309
+ this.notify();
282
310
  return;
283
311
  }
284
312
 
@@ -286,6 +314,13 @@ export class OrganisationService extends BaseService implements IOrganisationSer
286
314
  const now = Date.now();
287
315
  if (now - this.lastLoadTimeRef < 2000) {
288
316
  console.log("OrganisationService", "Too soon since last load, skipping");
317
+ // Ensure loading state is correct
318
+ if (this._organisations.length > 0 || this._selectedOrganisation) {
319
+ this._isLoading = false;
320
+ } else {
321
+ this._isLoading = true;
322
+ }
323
+ this.notify();
289
324
  return;
290
325
  }
291
326
 
@@ -305,9 +340,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
305
340
  this.notify();
306
341
 
307
342
  try {
308
- DebugLogger.log("OrganisationService", "Loading organisations for user:", this.user.id);
309
-
310
- // Debug: Log Supabase client configuration
311
343
  console.log("[OrganisationService] Supabase client ready:", {
312
344
  isConnected: !!this.supabaseClient,
313
345
  hasAuth: !!this.supabaseClient.auth,
@@ -418,8 +450,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
418
450
  }
419
451
  }
420
452
 
421
- DebugLogger.log("OrganisationService", "Raw memberships data:", memberships);
422
-
423
453
  if (!memberships || memberships.length === 0) {
424
454
  throw new Error('User has no active organisation memberships') as OrganisationSecurityError;
425
455
  }
@@ -451,8 +481,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
451
481
  throw new Error('No valid organisation IDs found in memberships') as OrganisationSecurityError;
452
482
  }
453
483
 
454
- DebugLogger.log("OrganisationService", "Valid organisation IDs:", organisationIds);
455
-
456
484
  // Check if request was aborted before making organisations query
457
485
  if (abortSignal.aborted) {
458
486
  throw new Error('Request aborted');
@@ -486,8 +514,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
486
514
  throw new Error('User has no access to active organisations') as OrganisationSecurityError;
487
515
  }
488
516
 
489
- DebugLogger.log("OrganisationService", "Active organisations:", activeOrgs);
490
-
491
517
  this._organisations = activeOrgs;
492
518
  this._userMemberships = memberships as OrganisationMembership[];
493
519
 
@@ -507,7 +533,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
507
533
  const validPersistedOrg = activeOrgs.find(org => org.id === persistedOrg.id);
508
534
  if (validPersistedOrg) {
509
535
  initialOrg = validPersistedOrg;
510
- DebugLogger.log("OrganisationService", "Restored persisted organisation:", initialOrg.display_name);
511
536
  } else {
512
537
  console.warn("[OrganisationService] Persisted organisation not found in active orgs, clearing cache");
513
538
  localStorage.removeItem('pace-core-selected-organisation');
@@ -527,10 +552,9 @@ export class OrganisationService extends BaseService implements IOrganisationSer
527
552
  if (!initialOrg) {
528
553
  const adminMembership = memberships.find((m: any) => m.role === 'org_admin');
529
554
  if (adminMembership) {
530
- const foundOrg = organisations.find((org: any) => org.id === adminMembership.organisation_id);
555
+ const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
531
556
  if (foundOrg) {
532
557
  initialOrg = foundOrg;
533
- DebugLogger.log("OrganisationService", "Selected org_admin organisation:", initialOrg.display_name);
534
558
  }
535
559
  }
536
560
  }
@@ -538,7 +562,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
538
562
  // 3. Fall back to first organisation
539
563
  if (!initialOrg) {
540
564
  initialOrg = activeOrgs[0];
541
- DebugLogger.log("OrganisationService", "Selected first organisation:", initialOrg.display_name);
542
565
  }
543
566
 
544
567
  if (!initialOrg) {
@@ -550,11 +573,8 @@ export class OrganisationService extends BaseService implements IOrganisationSer
550
573
  // Persist selection
551
574
  localStorage.setItem('pace-core-selected-organisation', JSON.stringify(initialOrg));
552
575
 
553
- DebugLogger.log("OrganisationService", "Organisation context established:", {
554
- selectedOrganisation: initialOrg.display_name,
555
- totalOrganisations: activeOrgs.length,
556
- userRole: roleMap.get(initialOrg.id)
557
- });
576
+ // Set database organisation context
577
+ await this.setDatabaseOrganisationContext(initialOrg);
558
578
 
559
579
  // Reset retry count and failed flag on success
560
580
  this.retryCount = 0;
@@ -46,7 +46,7 @@ describe('AuthService', () => {
46
46
  expect(authService.getUser()).toBeNull();
47
47
  expect(authService.getSession()).toBeNull();
48
48
  expect(authService.isAuthenticated()).toBe(false);
49
- expect(authService.isLoading()).toBe(true);
49
+ expect(authService.isLoading()).toBe(false);
50
50
  expect(authService.getError()).toBeNull();
51
51
  });
52
52
 
@@ -95,7 +95,7 @@ describe('EventService', () => {
95
95
  it('should initialize with default state', () => {
96
96
  expect(eventService.getEvents()).toEqual([]);
97
97
  expect(eventService.getSelectedEvent()).toBeNull();
98
- expect(eventService.isLoading()).toBe(true);
98
+ expect(eventService.isLoading()).toBe(false);
99
99
  expect(eventService.getError()).toBeNull();
100
100
  });
101
101
 
@@ -126,7 +126,7 @@ describe('OrganisationService', () => {
126
126
  expect(organisationService.getSelectedOrganisation()).toBeNull();
127
127
  expect(organisationService.getOrganisations()).toEqual([]);
128
128
  expect(organisationService.getUserMemberships()).toEqual([]);
129
- expect(organisationService.isLoading()).toBe(true);
129
+ expect(organisationService.isLoading()).toBe(false);
130
130
  expect(organisationService.getError()).toBeNull();
131
131
  expect(organisationService.hasValidOrganisationContext()).toBe(false);
132
132
  });
@@ -75,6 +75,14 @@ export abstract class BaseService {
75
75
  return this.isInitialized;
76
76
  }
77
77
 
78
+ /**
79
+ * Reset initialization state (allows re-initialization)
80
+ * Use when dependencies change and service needs to re-initialize
81
+ */
82
+ protected resetInitialization(): void {
83
+ this.isInitialized = false;
84
+ }
85
+
78
86
  /**
79
87
  * Override in subclasses to implement initialization logic
80
88
  */