@jmruthers/pace-core 0.6.10 → 0.6.11

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 (726) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +13 -3
  5. package/audit-tool/audits/03-architecture.cjs +78 -4
  6. package/audit-tool/audits/04-code-quality.cjs +9 -2
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +105 -14
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +1 -0
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +41 -7
  19. package/cursor-rules/06-security-rbac.mdc +2 -1
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/{DataTable-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
  24. package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
  25. package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
  26. package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
  29. package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
  30. package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
  31. package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
  32. package/dist/chunk-44CNXN4P.js +15 -0
  33. package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
  34. package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
  35. package/dist/chunk-CU2BU2MQ.js +2 -0
  36. package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
  37. package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
  38. package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
  39. package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
  40. package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
  41. package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
  42. package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
  43. package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
  44. package/dist/chunk-WY6Y7KC3.js +264 -0
  45. package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
  46. package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
  47. package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
  48. package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
  49. package/dist/components.d.ts +8 -7
  50. package/dist/components.js +17 -15
  51. package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
  52. package/dist/eslint-rules/index.cjs +3 -0
  53. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  54. package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
  55. package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
  56. package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
  57. package/dist/hooks.d.ts +22 -9
  58. package/dist/hooks.js +34 -25
  59. package/dist/icons/index.d.ts +1 -0
  60. package/dist/icons/index.js +1 -0
  61. package/dist/index.d.ts +66 -177
  62. package/dist/index.js +316 -340
  63. package/dist/pagination-BW1mqywp.d.ts +201 -0
  64. package/dist/providers.d.ts +6 -5
  65. package/dist/providers.js +5 -3
  66. package/dist/rbac/index.d.ts +123 -138
  67. package/dist/rbac/index.js +10 -8
  68. package/dist/theming/runtime.d.ts +19 -2
  69. package/dist/theming/runtime.js +1 -1
  70. package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
  71. package/dist/types.d.ts +17 -10
  72. package/dist/types.js +1 -0
  73. package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
  74. package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
  75. package/dist/utils.d.ts +163 -145
  76. package/dist/utils.js +42 -25
  77. package/docs/api/modules.md +782 -643
  78. package/docs/api-reference/rpc-functions.md +12 -3
  79. package/docs/core-concepts/rbac-system.md +8 -0
  80. package/docs/getting-started/cursor-rules.md +17 -20
  81. package/docs/getting-started/dependencies.md +1 -1
  82. package/docs/getting-started/setup.md +235 -0
  83. package/docs/implementation-guides/authentication.md +27 -0
  84. package/docs/implementation-guides/data-tables.md +176 -3
  85. package/docs/migration/ApiResult-migration.md +25 -0
  86. package/docs/rbac/api-reference.md +33 -31
  87. package/docs/standards/0-standards-overview.md +50 -15
  88. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  89. package/docs/standards/2-project-structure-standards.md +33 -16
  90. package/docs/standards/3-architecture-standards.md +41 -1
  91. package/docs/standards/4-code-quality-standards.md +26 -6
  92. package/docs/standards/5-styling-standards.md +35 -1
  93. package/docs/standards/6-security-rbac-standards.md +66 -0
  94. package/docs/standards/7-api-tech-stack-standards.md +25 -14
  95. package/docs/standards/8-testing-documentation-standards.md +31 -0
  96. package/docs/standards/9-operations-standards.md +19 -0
  97. package/docs/standards/README.md +20 -201
  98. package/docs/testing/test-setup-for-consumers.md +2 -0
  99. package/docs/troubleshooting/common-issues.md +17 -1
  100. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  101. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  102. package/eslint-config-pace-core.cjs +20 -0
  103. package/package.json +14 -20
  104. package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
  105. package/scripts/setup.cjs +536 -0
  106. package/scripts/validate.cjs +480 -0
  107. package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
  108. package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
  109. package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
  110. package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
  111. package/src/__tests__/helpers/test-providers.tsx +37 -39
  112. package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
  113. package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
  114. package/src/assets/app-icons/index.test.ts +304 -0
  115. package/src/components/AddressField/AddressField.test.tsx +1 -1
  116. package/src/components/AddressField/AddressField.tsx +238 -212
  117. package/src/components/Button/Button.tsx +1 -1
  118. package/src/components/Card/Card.test.tsx +172 -17
  119. package/src/components/Card/Card.tsx +19 -10
  120. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  121. package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
  122. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  123. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  124. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  125. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  126. package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
  127. package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
  128. package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
  129. package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
  130. package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
  131. package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
  132. package/src/components/DataTable/DataTable.test.tsx +787 -416
  133. package/src/components/DataTable/DataTable.tsx +12 -12
  134. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  135. package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
  136. package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
  137. package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
  138. package/src/components/DataTable/TESTING.md +101 -0
  139. package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
  140. package/src/components/DataTable/components/DataTableCore.tsx +104 -864
  141. package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
  142. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +61 -559
  144. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  145. package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
  146. package/src/components/DataTable/context/DataTableContext.tsx +7 -6
  147. package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
  148. package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
  149. package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
  150. package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
  151. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
  152. package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
  153. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  154. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  155. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  156. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  157. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  158. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  159. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  160. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  161. package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
  162. package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
  163. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  164. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  165. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  166. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  167. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  168. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  169. package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
  170. package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
  171. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  172. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  173. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  174. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  175. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  176. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  177. package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
  178. package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
  179. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
  180. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
  181. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  182. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  183. package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
  184. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
  185. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
  186. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
  187. package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
  188. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
  189. package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
  190. package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
  191. package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
  192. package/src/components/DataTable/index.ts +18 -17
  193. package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
  194. package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
  195. package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
  196. package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
  197. package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
  198. package/src/components/DataTable/styles.ts +0 -1
  199. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  200. package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
  201. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  202. package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
  203. package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
  204. package/src/components/DataTable/types/actions.ts +71 -0
  205. package/src/components/DataTable/types/base.ts +39 -0
  206. package/src/components/DataTable/types/columns.ts +125 -0
  207. package/src/components/DataTable/types/export.ts +32 -0
  208. package/src/components/DataTable/types/features.ts +81 -0
  209. package/src/components/DataTable/types/hierarchical.ts +44 -0
  210. package/src/components/DataTable/types/index.ts +43 -0
  211. package/src/components/DataTable/types/pagination.ts +85 -0
  212. package/src/components/DataTable/types/performance.ts +47 -0
  213. package/src/components/DataTable/types/props.ts +62 -0
  214. package/src/components/DataTable/types/rbac.ts +45 -0
  215. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
  216. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  217. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
  218. package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
  219. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  220. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  221. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  222. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  223. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  224. package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
  225. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  226. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  227. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  228. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  229. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  230. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  231. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  232. package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
  233. package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
  234. package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
  235. package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
  236. package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
  237. package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
  238. package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
  239. package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
  240. package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
  241. package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
  242. package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
  243. package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
  244. package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
  245. package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
  246. package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
  247. package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
  248. package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
  249. package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
  250. package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
  251. package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
  252. package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
  253. package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
  254. package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
  255. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  256. package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
  257. package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
  258. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
  259. package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
  260. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
  261. package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
  262. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
  263. package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
  264. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  265. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  266. package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
  267. package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
  268. package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
  269. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  270. package/src/components/DataTable/utils/csvParse.ts +65 -0
  271. package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
  272. package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
  273. package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
  274. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  275. package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
  276. package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
  277. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  278. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  279. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  280. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  281. package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
  282. package/src/components/DataTable/utils/paginationUtils.ts +6 -3
  283. package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
  284. package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
  285. package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
  286. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
  287. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  288. package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
  289. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  290. package/src/components/Dialog/Dialog.test.tsx +896 -89
  291. package/src/components/Dialog/Dialog.tsx +174 -882
  292. package/src/components/Dialog/dialogLock.test.ts +238 -0
  293. package/src/components/Dialog/dialogLock.ts +98 -0
  294. package/src/components/Dialog/index.ts +2 -0
  295. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  296. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  297. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  298. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  299. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  300. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  301. package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
  302. package/src/components/FileDisplay/FileDisplay.tsx +24 -656
  303. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  304. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  305. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  306. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  307. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  308. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  309. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  310. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  311. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  312. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  313. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  314. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  315. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  316. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  317. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  318. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  319. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  320. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  321. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  322. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  323. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  324. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  325. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  326. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  327. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  328. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  329. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
  330. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  331. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
  332. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  333. package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
  334. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  335. package/src/components/FileUpload/FileUpload.test.tsx +16 -10
  336. package/src/components/FileUpload/FileUpload.tsx +107 -525
  337. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  338. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  339. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  340. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  341. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  342. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  343. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  344. package/src/components/Footer/Footer.test.tsx +6 -292
  345. package/src/components/Footer/Footer.tsx +8 -125
  346. package/src/components/Form/Form.test.tsx +44 -27
  347. package/src/components/Form/Form.tsx +64 -287
  348. package/src/components/Form/useFormPersistence.ts +257 -0
  349. package/src/components/Header/Header.test.tsx +17 -18
  350. package/src/components/Header/Header.tsx +10 -1
  351. package/src/components/Input/Input.tsx +1 -1
  352. package/src/components/Label/Label.test.tsx +1 -1
  353. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
  354. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  355. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
  356. package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
  357. package/src/components/NavigationMenu/index.ts +6 -1
  358. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  359. package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
  360. package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
  361. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  362. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
  363. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
  364. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
  365. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
  366. package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
  367. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  368. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  369. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  370. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  371. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  372. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  373. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  374. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
  375. package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
  376. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  377. package/src/components/Progress/Progress.tsx +1 -2
  378. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
  379. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  380. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  381. package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
  382. package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
  383. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
  384. package/src/components/Select/Select.test.tsx +1 -1
  385. package/src/components/Select/Select.tsx +28 -18
  386. package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
  387. package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
  388. package/src/components/Select/{utils/text.ts → text.ts} +1 -1
  389. package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
  390. package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
  391. package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
  392. package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
  393. package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
  394. package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
  395. package/src/components/Table/Table.test.tsx +348 -0
  396. package/src/components/Tabs/Tabs.test.tsx +270 -0
  397. package/src/components/Tabs/Tabs.tsx +1 -1
  398. package/src/components/Toast/Toast.test.tsx +420 -0
  399. package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
  400. package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
  401. package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
  402. package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
  403. package/src/hooks/index.ts +7 -4
  404. package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
  405. package/src/hooks/public/usePublicEvent.test.ts +1 -1
  406. package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
  407. package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
  408. package/src/hooks/services/useAuth.ts +9 -7
  409. package/src/hooks/useAddressAutocomplete.test.ts +22 -22
  410. package/src/hooks/useAddressAutocomplete.ts +90 -75
  411. package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
  412. package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
  413. package/src/hooks/useDataTablePerformance.ts +100 -120
  414. package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
  415. package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
  416. package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
  417. package/src/hooks/useEventTheme.test.ts +4 -1
  418. package/src/hooks/useEventTheme.ts +49 -21
  419. package/src/hooks/useEvents.ts +41 -1
  420. package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
  421. package/src/hooks/useFileReference.test.ts +44 -41
  422. package/src/hooks/useFileReference.ts +182 -173
  423. package/src/hooks/useFileUrl.ts +1 -1
  424. package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
  425. package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
  426. package/src/hooks/useFileUrlCache.ts +1 -1
  427. package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
  428. package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
  429. package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
  430. package/src/hooks/useInactivityTracker.ts +138 -131
  431. package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
  432. package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
  433. package/src/hooks/useIsPrint.ts +62 -0
  434. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  435. package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
  436. package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
  437. package/src/hooks/useOrganisationSecurity.test.ts +3 -3
  438. package/src/hooks/useOrganisationSecurity.ts +190 -201
  439. package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
  440. package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
  441. package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
  442. package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
  443. package/src/hooks/usePermissionCache.ts +276 -271
  444. package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
  445. package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
  446. package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
  447. package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
  448. package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
  449. package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
  450. package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
  451. package/src/hooks/useQueryCache.ts +0 -2
  452. package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
  453. package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
  454. package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
  455. package/src/hooks/useStorage.ts +21 -16
  456. package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
  457. package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
  458. package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
  459. package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
  460. package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
  461. package/src/icons/index.ts +2 -0
  462. package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
  463. package/src/index.ts +15 -7
  464. package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
  465. package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
  466. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  467. package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
  468. package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
  469. package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
  470. package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
  471. package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
  472. package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
  473. package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
  474. package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
  475. package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
  476. package/src/providers/services/UnifiedAuthContext.ts +30 -27
  477. package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
  478. package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
  479. package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
  480. package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
  481. package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
  482. package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
  483. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  484. package/src/providers/useInactivity.test-helper.ts +27 -0
  485. package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
  486. package/src/rbac/adapters.test.tsx +22 -22
  487. package/src/rbac/adapters.tsx +29 -29
  488. package/src/rbac/api.test.ts +973 -42
  489. package/src/rbac/api.ts +228 -253
  490. package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
  491. package/src/rbac/audit.ts +4 -1
  492. package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
  493. package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
  494. package/src/rbac/cache-invalidation.test.ts +715 -0
  495. package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
  496. package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
  497. package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
  498. package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
  499. package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
  500. package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
  501. package/src/rbac/components/PagePermissionGuard.tsx +177 -372
  502. package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
  503. package/src/rbac/config.ts +58 -18
  504. package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
  505. package/src/rbac/engine.test.ts +494 -0
  506. package/src/rbac/errors.ts +89 -55
  507. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  508. package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
  509. package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
  510. package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
  511. package/src/rbac/hooks/permissions/useCan.ts +170 -252
  512. package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
  513. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
  514. package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
  515. package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
  516. package/src/rbac/hooks/useCan.test.ts +42 -42
  517. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  518. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  519. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  520. package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
  521. package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
  522. package/src/rbac/hooks/usePermissions.test.ts +54 -54
  523. package/src/rbac/hooks/useRBAC.test.ts +313 -217
  524. package/src/rbac/hooks/useRBAC.ts +145 -81
  525. package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
  526. package/src/rbac/hooks/useResourcePermissions.ts +68 -134
  527. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  528. package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
  529. package/src/rbac/hooks/useRoleManagement.ts +153 -585
  530. package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
  531. package/src/rbac/hooks/useSecureSupabase.ts +10 -2
  532. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  533. package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
  534. package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
  535. package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
  536. package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
  537. package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
  538. package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
  539. package/src/rbac/request-deduplication.test.ts +14 -9
  540. package/src/rbac/request-deduplication.ts +5 -4
  541. package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
  542. package/src/rbac/secureClient.test.ts +514 -83
  543. package/src/rbac/secureClient.ts +8 -2
  544. package/src/rbac/security.test.ts +323 -0
  545. package/src/rbac/types/roleManagement.ts +66 -0
  546. package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
  547. package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
  548. package/src/rbac/utils/contextValidator.ts +5 -1
  549. package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
  550. package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
  551. package/src/rbac/utils/eventContext.ts +37 -33
  552. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  553. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  554. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  555. package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
  556. package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
  557. package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
  558. package/src/services/AuthService.ts +184 -205
  559. package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
  560. package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
  561. package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
  562. package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
  563. package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
  564. package/src/services/EventService.ts +242 -312
  565. package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
  566. package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
  567. package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
  568. package/src/services/InactivityService.ts +172 -213
  569. package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
  570. package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
  571. package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
  572. package/src/services/OrganisationService.ts +184 -238
  573. package/src/services/base/BaseService.test.ts +1 -1
  574. package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
  575. package/src/services/interfaces/IAuthService.ts +10 -9
  576. package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
  577. package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
  578. package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
  579. package/src/styles/core.css +243 -12
  580. package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
  581. package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
  582. package/src/theming/runtime.ts +71 -2
  583. package/src/types/api-result.ts +53 -0
  584. package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
  585. package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
  586. package/src/types/database.generated.ts +45 -10
  587. package/src/types/event.ts +38 -18
  588. package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
  589. package/src/types/file-reference.ts +37 -12
  590. package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
  591. package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
  592. package/src/types/index.ts +3 -0
  593. package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
  594. package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
  595. package/src/types/organisation.ts +15 -15
  596. package/src/types/supabase.ts +13 -4
  597. package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
  598. package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
  599. package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  600. package/src/utils/app/appIdResolver.test.ts +98 -71
  601. package/src/utils/app/appIdResolver.ts +31 -20
  602. package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
  603. package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
  604. package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
  605. package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
  606. package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
  607. package/src/utils/context/organisationContext.test.ts +105 -91
  608. package/src/utils/context/organisationContext.ts +29 -40
  609. package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
  610. package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
  611. package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
  612. package/src/utils/core/mergeRefs.ts +24 -0
  613. package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
  614. package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
  615. package/src/utils/dynamic/createLazyComponent.tsx +9 -1
  616. package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
  617. package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
  618. package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
  619. package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
  620. package/src/utils/file-reference/index.ts +330 -347
  621. package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
  622. package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
  623. package/src/utils/formatting/formatNumber.test.ts +1 -1
  624. package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
  625. package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
  626. package/src/utils/google-places/googlePlacesUtils.ts +67 -99
  627. package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
  628. package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
  629. package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
  630. package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
  631. package/src/utils/location/location.test.ts +1 -1
  632. package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
  633. package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
  634. package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
  635. package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  636. package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
  637. package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  638. package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
  639. package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
  640. package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
  641. package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
  642. package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
  643. package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
  644. package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
  645. package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
  646. package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
  647. package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
  648. package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
  649. package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
  650. package/src/utils/security/auth-utils.ts +34 -23
  651. package/src/utils/security/secureDataAccess.ts +241 -281
  652. package/src/utils/security/secureErrors.test.ts +1 -1
  653. package/src/utils/security/secureStorage.test.ts +1 -1
  654. package/src/utils/security/security.test.ts +25 -17
  655. package/src/utils/security/security.ts +15 -18
  656. package/src/utils/security/securityMonitor.test.ts +1 -1
  657. package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
  658. package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
  659. package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
  660. package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
  661. package/src/utils/storage/helpers.test.ts +88 -102
  662. package/src/utils/storage/helpers.ts +173 -251
  663. package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
  664. package/src/utils/storage/types.ts +7 -0
  665. package/src/utils/supabase/createBaseClient.test.ts +1 -1
  666. package/src/utils/timezone/timezone.test.ts +1 -1
  667. package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
  668. package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
  669. package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
  670. package/src/utils/validation/csrf.ts +42 -41
  671. package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
  672. package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
  673. package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
  674. package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
  675. package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
  676. package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  677. package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
  678. package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
  679. package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
  680. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
  681. package/dist/chunk-KPYQWGFQ.js +0 -183
  682. package/dist/types-D05dCGma.d.ts +0 -521
  683. package/scripts/eslint-audit.cjs +0 -222
  684. package/scripts/generate-docs.js +0 -157
  685. package/scripts/install-cursor-rules.cjs +0 -255
  686. package/scripts/install-eslint-config.cjs +0 -349
  687. package/scripts/setup-build-cache.js +0 -73
  688. package/scripts/validate-pre-publish.js +0 -145
  689. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  690. package/src/__tests__/public-recipe-view.test.ts +0 -228
  691. package/src/__tests__/rls-policies.test.ts +0 -472
  692. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  693. package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
  694. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
  695. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
  696. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
  697. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
  698. package/src/components/DataTable/core/ActionManager.ts +0 -235
  699. package/src/components/DataTable/core/ColumnManager.ts +0 -204
  700. package/src/components/DataTable/core/DataManager.ts +0 -190
  701. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  702. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  703. package/src/components/DataTable/core/StateManager.ts +0 -312
  704. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
  705. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
  706. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
  707. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
  708. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
  709. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
  710. package/src/components/DataTable/core/interfaces.ts +0 -338
  711. package/src/components/DataTable/types.ts +0 -764
  712. package/src/hooks/public/usePublicFileDisplay.ts +0 -534
  713. package/src/hooks/useFileDisplay.ts +0 -748
  714. package/src/providers/OrganisationProvider.test.tsx +0 -40
  715. package/src/providers/OrganisationProvider.tsx +0 -92
  716. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  717. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
  718. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
  719. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
  720. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  721. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  722. /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
  723. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  724. /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
  725. /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
  726. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -1,10 +1,13 @@
1
- import { isRBACInitialized, setupRBAC } from './chunk-LNHFAF4X.js';
1
+ import { setPrintAppName } from './chunk-D6BMFMQZ.js';
2
+ import { isRBACInitialized, setupRBAC } from './chunk-7A6IMHH2.js';
2
3
  import { assertOrganisationId, assertUserId } from './chunk-4SXLQIZO.js';
3
4
  import { secureStorage } from './chunk-RMLY6KB5.js';
4
5
  import { createLogger, logger } from './chunk-BTHN5MKC.js';
6
+ import { err, ok } from './chunk-44CNXN4P.js';
5
7
  import { createContext, useRef, useEffect, useState, useMemo, useContext, useReducer, useCallback } from 'react';
6
8
  import { AuthError } from '@supabase/supabase-js';
7
9
  import { jsx } from 'react/jsx-runtime';
10
+ import { flushSync } from 'react-dom';
8
11
 
9
12
  // src/services/base/BaseService.ts
10
13
  var BaseService = class {
@@ -74,6 +77,13 @@ var BaseService = class {
74
77
  }
75
78
  };
76
79
 
80
+ // src/utils/security/auth-utils.ts
81
+ function toApiError(error) {
82
+ const message = error.message || "An unexpected error occurred";
83
+ const code = "status" in error && typeof error.status === "number" ? `AUTH_${error.status}` : error.name || "AUTH_ERROR";
84
+ return { code, message };
85
+ }
86
+
77
87
  // src/services/AuthService.ts
78
88
  var _AuthService = class _AuthService extends BaseService {
79
89
  // Track previous auth state to detect transitions
@@ -135,7 +145,7 @@ var _AuthService = class _AuthService extends BaseService {
135
145
  const error = new AuthError("Supabase client not available");
136
146
  this.authError = error;
137
147
  this.notify();
138
- return { user: null, session: null, error };
148
+ return err(toApiError(error));
139
149
  }
140
150
  try {
141
151
  const { data, error } = await this.supabaseClient.auth.signInWithPassword({
@@ -146,24 +156,25 @@ var _AuthService = class _AuthService extends BaseService {
146
156
  this.authError = error;
147
157
  this.user = null;
148
158
  this.session = null;
149
- } else {
150
- this.authError = null;
151
- this.user = data.user;
152
- this.session = data.session;
153
- if (!this.wasAuthenticatedRef && data.user) {
154
- this.clearPersistenceOnLogin(null, true);
155
- this.wasAuthenticatedRef = true;
156
- }
159
+ this.notify();
160
+ return err(toApiError(error));
161
+ }
162
+ this.authError = null;
163
+ this.user = data.user;
164
+ this.session = data.session;
165
+ if (!this.wasAuthenticatedRef && data.user) {
166
+ this.clearPersistenceOnLogin(null, true);
167
+ this.wasAuthenticatedRef = true;
157
168
  }
158
169
  this.notify();
159
- return { user: data.user, session: data.session, error };
170
+ return ok({ user: data.user, session: data.session });
160
171
  } catch (error) {
161
172
  const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
162
173
  this.authError = authError;
163
174
  this.user = null;
164
175
  this.session = null;
165
176
  this.notify();
166
- return { user: null, session: null, error: authError };
177
+ return err(toApiError(authError));
167
178
  }
168
179
  }
169
180
  async signUp(email, password) {
@@ -171,7 +182,7 @@ var _AuthService = class _AuthService extends BaseService {
171
182
  const error = new AuthError("Supabase client not available");
172
183
  this.authError = error;
173
184
  this.notify();
174
- return { user: null, session: null, error };
185
+ return err(toApiError(error));
175
186
  }
176
187
  try {
177
188
  const { data, error } = await this.supabaseClient.auth.signUp({
@@ -182,24 +193,25 @@ var _AuthService = class _AuthService extends BaseService {
182
193
  this.authError = error;
183
194
  this.user = null;
184
195
  this.session = null;
185
- } else {
186
- this.authError = null;
187
- this.user = data.user;
188
- this.session = data.session;
189
- if (!this.wasAuthenticatedRef && data.user) {
190
- this.clearPersistenceOnLogin(null, true);
191
- this.wasAuthenticatedRef = true;
192
- }
196
+ this.notify();
197
+ return err(toApiError(error));
198
+ }
199
+ this.authError = null;
200
+ this.user = data.user;
201
+ this.session = data.session;
202
+ if (!this.wasAuthenticatedRef && data.user) {
203
+ this.clearPersistenceOnLogin(null, true);
204
+ this.wasAuthenticatedRef = true;
193
205
  }
194
206
  this.notify();
195
- return { user: data.user, session: data.session, error };
207
+ return ok({ user: data.user, session: data.session });
196
208
  } catch (error) {
197
209
  const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
198
210
  this.authError = authError;
199
211
  this.user = null;
200
212
  this.session = null;
201
213
  this.notify();
202
- return { user: null, session: null, error: authError };
214
+ return err(toApiError(authError));
203
215
  }
204
216
  }
205
217
  async signOut() {
@@ -207,36 +219,47 @@ var _AuthService = class _AuthService extends BaseService {
207
219
  const error = new AuthError("Supabase client not available");
208
220
  this.authError = error;
209
221
  this.notify();
210
- return { user: null, session: null, error };
222
+ return err(toApiError(error));
211
223
  }
212
- try {
213
- const { error } = await this.supabaseClient.auth.signOut();
224
+ const clearLocalState = () => {
225
+ this.authError = null;
226
+ this.user = null;
227
+ this.session = null;
214
228
  try {
215
229
  sessionStorage.clear();
216
230
  } catch (storageError) {
217
231
  logger.warn("AuthService", "Failed to clear sessionStorage", { error: storageError });
218
232
  }
233
+ this.notify();
234
+ };
235
+ try {
236
+ const { error } = await this.supabaseClient.auth.signOut();
219
237
  if (error) {
220
- this.authError = error;
221
- } else {
222
- this.authError = null;
223
- this.user = null;
224
- this.session = null;
238
+ logger.warn("AuthService", "signOut (global) failed, clearing local state and trying local scope", {
239
+ message: error.message,
240
+ status: error.status
241
+ });
242
+ clearLocalState();
243
+ const { error: localError } = await this.supabaseClient.auth.signOut({ scope: "local" });
244
+ if (localError) {
245
+ logger.warn("AuthService", "signOut (local) also failed", { message: localError.message });
246
+ }
247
+ return err(toApiError(error));
225
248
  }
226
- this.notify();
227
- return { user: null, session: null, error };
249
+ clearLocalState();
250
+ return ok({ user: null, session: null });
228
251
  } catch (error) {
252
+ logger.warn("AuthService", "signOut threw, clearing local state and trying local scope", {
253
+ message: error instanceof Error ? error.message : String(error)
254
+ });
255
+ clearLocalState();
229
256
  try {
230
- sessionStorage.clear();
231
- } catch (storageError) {
232
- logger.warn("AuthService", "Failed to clear sessionStorage", { error: storageError });
257
+ await this.supabaseClient.auth.signOut({ scope: "local" });
258
+ } catch (_localError) {
233
259
  }
234
260
  const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
235
261
  this.authError = authError;
236
- this.user = null;
237
- this.session = null;
238
- this.notify();
239
- return { user: null, session: null, error: authError };
262
+ return err(toApiError(authError));
240
263
  }
241
264
  }
242
265
  async resetPassword(email) {
@@ -244,22 +267,23 @@ var _AuthService = class _AuthService extends BaseService {
244
267
  const error = new AuthError("Supabase client not available");
245
268
  this.authError = error;
246
269
  this.notify();
247
- return { user: null, session: null, error };
270
+ return err(toApiError(error));
248
271
  }
249
272
  try {
250
273
  const { error } = await this.supabaseClient.auth.resetPasswordForEmail(email);
251
274
  if (error) {
252
275
  this.authError = error;
253
- } else {
254
- this.authError = null;
276
+ this.notify();
277
+ return err(toApiError(error));
255
278
  }
279
+ this.authError = null;
256
280
  this.notify();
257
- return { user: null, session: null, error };
281
+ return ok({ user: this.user, session: this.session });
258
282
  } catch (error) {
259
283
  const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
260
284
  this.authError = authError;
261
285
  this.notify();
262
- return { user: null, session: null, error: authError };
286
+ return err(toApiError(authError));
263
287
  }
264
288
  }
265
289
  async updatePassword(password) {
@@ -267,7 +291,7 @@ var _AuthService = class _AuthService extends BaseService {
267
291
  const error = new AuthError("Supabase client not available");
268
292
  this.authError = error;
269
293
  this.notify();
270
- return { user: null, session: null, error };
294
+ return err(toApiError(error));
271
295
  }
272
296
  try {
273
297
  const { error } = await this.supabaseClient.auth.updateUser({
@@ -275,16 +299,17 @@ var _AuthService = class _AuthService extends BaseService {
275
299
  });
276
300
  if (error) {
277
301
  this.authError = error;
278
- } else {
279
- this.authError = null;
302
+ this.notify();
303
+ return err(toApiError(error));
280
304
  }
305
+ this.authError = null;
281
306
  this.notify();
282
- return { user: null, session: null, error };
307
+ return ok({ user: this.user, session: this.session });
283
308
  } catch (error) {
284
- const authError = error;
309
+ const authError = error instanceof AuthError ? error : error;
285
310
  this.authError = authError;
286
311
  this.notify();
287
- return { user: null, session: null, error: authError };
312
+ return err(toApiError(authError));
288
313
  }
289
314
  }
290
315
  async refreshSession() {
@@ -292,7 +317,7 @@ var _AuthService = class _AuthService extends BaseService {
292
317
  const error = new AuthError("Supabase client not available");
293
318
  this.authError = error;
294
319
  this.notify();
295
- return { user: null, session: null, error };
320
+ return err(toApiError(error));
296
321
  }
297
322
  try {
298
323
  const { data, error } = await this.supabaseClient.auth.refreshSession();
@@ -300,29 +325,29 @@ var _AuthService = class _AuthService extends BaseService {
300
325
  this.authError = error;
301
326
  this.user = null;
302
327
  this.session = null;
328
+ this.notify();
329
+ return err(toApiError(error));
330
+ }
331
+ this.authError = null;
332
+ if (data?.user && data?.session) {
333
+ this.user = data.user;
334
+ this.session = data.session;
303
335
  } else {
304
- this.authError = null;
305
- if (data?.user && data?.session) {
306
- this.user = data.user;
307
- this.session = data.session;
308
- } else {
309
- this.user = null;
310
- this.session = null;
311
- }
336
+ this.user = null;
337
+ this.session = null;
312
338
  }
313
339
  this.notify();
314
- return {
340
+ return ok({
315
341
  user: data?.user && data?.session ? data.user : null,
316
- session: data?.session ?? null,
317
- error
318
- };
342
+ session: data?.session ?? null
343
+ });
319
344
  } catch (error) {
320
345
  const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
321
346
  this.authError = authError;
322
347
  this.user = null;
323
348
  this.session = null;
324
349
  this.notify();
325
- return { user: null, session: null, error: authError };
350
+ return err(toApiError(authError));
326
351
  }
327
352
  }
328
353
  // Lifecycle methods
@@ -432,6 +457,62 @@ var _AuthService = class _AuthService extends BaseService {
432
457
  logger.warn("AuthService", `Failed to clear persistence [ID:${this.instanceId}]:`, error);
433
458
  }
434
459
  }
460
+ handleSignedOut(session) {
461
+ this.session = null;
462
+ this.user = null;
463
+ this.authError = null;
464
+ this.wasAuthenticatedRef = false;
465
+ if (session?.user) {
466
+ this.trackSession("logout", session).catch((err2) => {
467
+ logger.warn("AuthService", `Failed to track logout session [ID:${this.instanceId}]:`, err2);
468
+ });
469
+ }
470
+ }
471
+ handleSignedInOrTokenRefreshed(event, session, wasAuthenticated, isNowAuthenticated, userChanged, previousUserId) {
472
+ this.session = session;
473
+ this.user = session?.user ?? null;
474
+ if (session?.user) {
475
+ this.authError = null;
476
+ }
477
+ if (!wasAuthenticated && isNowAuthenticated && event === "SIGNED_IN") {
478
+ this.clearPersistenceOnLogin(null, true);
479
+ } else if (userChanged && previousUserId) {
480
+ this.clearPersistenceOnLogin(previousUserId, true);
481
+ }
482
+ this.wasAuthenticatedRef = isNowAuthenticated;
483
+ if (event === "SIGNED_IN" && session?.user) {
484
+ this.trackSession("login", session).catch((err2) => {
485
+ logger.warn("AuthService", `Failed to track login session [ID:${this.instanceId}]:`, err2);
486
+ });
487
+ }
488
+ }
489
+ handleInitialSession(session, wasAuthenticated) {
490
+ if (session) {
491
+ const previousUserId = this.user?.id ?? null;
492
+ const newUserId = session.user?.id ?? null;
493
+ const userChanged = previousUserId !== null && newUserId !== null && previousUserId !== newUserId;
494
+ this.session = session;
495
+ this.user = session.user ?? null;
496
+ this.authError = null;
497
+ if (userChanged && previousUserId) {
498
+ this.clearPersistenceOnLogin(previousUserId, true);
499
+ } else if (!wasAuthenticated && !!session.user) {
500
+ this.clearPersistenceOnLogin(null, true);
501
+ }
502
+ this.wasAuthenticatedRef = !!session.user;
503
+ const hasTimeoutError = this.sessionRestorationState.restorationError?.name === "SessionRestorationTimeoutError";
504
+ if (this.sessionRestorationState.isRestoring || this.sessionRestorationState.restorationError || hasTimeoutError && session) {
505
+ this.finishSessionRestoration();
506
+ }
507
+ } else {
508
+ this.wasAuthenticatedRef = false;
509
+ if (this.sessionRestorationState.isRestoring) {
510
+ this.finishSessionRestoration();
511
+ }
512
+ }
513
+ this.authLoading = false;
514
+ this.notify();
515
+ }
435
516
  async setupAuthStateListener() {
436
517
  if (!this.supabaseClient) {
437
518
  this.authLoading = false;
@@ -444,62 +525,22 @@ var _AuthService = class _AuthService extends BaseService {
444
525
  try {
445
526
  const wasAuthenticated = this.wasAuthenticatedRef;
446
527
  const isNowAuthenticated = !!session?.user;
447
- const previousUserId = this.user?.id || null;
448
- const newUserId = session?.user?.id || null;
528
+ const previousUserId = this.user?.id ?? null;
529
+ const newUserId = session?.user?.id ?? null;
449
530
  const userChanged = previousUserId !== null && newUserId !== null && previousUserId !== newUserId;
450
531
  if (event === "SIGNED_OUT") {
451
- this.session = null;
452
- this.user = null;
453
- this.authError = null;
454
- this.wasAuthenticatedRef = false;
455
- if (session?.user) {
456
- this.trackSession("logout", session).catch((err) => {
457
- logger.warn("AuthService", `Failed to track logout session [ID:${this.instanceId}]:`, err);
458
- });
459
- }
532
+ this.handleSignedOut(session);
460
533
  } else if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
461
- this.session = session;
462
- this.user = session?.user ?? null;
463
- if (session?.user) {
464
- this.authError = null;
465
- }
466
- if (!wasAuthenticated && isNowAuthenticated && event === "SIGNED_IN") {
467
- this.clearPersistenceOnLogin(null, true);
468
- } else if (userChanged && previousUserId) {
469
- this.clearPersistenceOnLogin(previousUserId, true);
470
- }
471
- this.wasAuthenticatedRef = isNowAuthenticated;
472
- if (event === "SIGNED_IN" && session?.user) {
473
- this.trackSession("login", session).catch((err) => {
474
- logger.warn("AuthService", `Failed to track login session [ID:${this.instanceId}]:`, err);
475
- });
476
- }
534
+ this.handleSignedInOrTokenRefreshed(
535
+ event,
536
+ session,
537
+ wasAuthenticated,
538
+ isNowAuthenticated,
539
+ userChanged,
540
+ previousUserId
541
+ );
477
542
  } else if (event === "INITIAL_SESSION") {
478
- if (session) {
479
- const previousUserId2 = this.user?.id || null;
480
- const newUserId2 = session.user?.id || null;
481
- const userChanged2 = previousUserId2 !== null && newUserId2 !== null && previousUserId2 !== newUserId2;
482
- this.session = session;
483
- this.user = session.user ?? null;
484
- this.authError = null;
485
- if (userChanged2 && previousUserId2) {
486
- this.clearPersistenceOnLogin(previousUserId2, true);
487
- } else if (!wasAuthenticated && !!session.user) {
488
- this.clearPersistenceOnLogin(null, true);
489
- }
490
- this.wasAuthenticatedRef = !!session.user;
491
- const hasTimeoutError = this.sessionRestorationState.restorationError?.name === "SessionRestorationTimeoutError";
492
- if (this.sessionRestorationState.isRestoring || this.sessionRestorationState.restorationError || hasTimeoutError && session) {
493
- this.finishSessionRestoration();
494
- }
495
- } else {
496
- this.wasAuthenticatedRef = false;
497
- if (this.sessionRestorationState.isRestoring) {
498
- this.finishSessionRestoration();
499
- }
500
- }
501
- this.authLoading = false;
502
- this.notify();
543
+ this.handleInitialSession(session, wasAuthenticated);
503
544
  return;
504
545
  }
505
546
  this.authLoading = false;
@@ -732,6 +773,7 @@ function AuthServiceProvider({ children, supabaseClient, appName }) {
732
773
  }), [authService, sessionRestoration]);
733
774
  return /* @__PURE__ */ jsx(AuthServiceContext.Provider, { value: contextValue, children });
734
775
  }
776
+ var OrganisationServiceContext = createContext(null);
735
777
 
736
778
  // src/services/OrganisationService.ts
737
779
  var _OrganisationService = class _OrganisationService extends BaseService {
@@ -959,7 +1001,8 @@ var _OrganisationService = class _OrganisationService extends BaseService {
959
1001
  this._isContextReady = true;
960
1002
  this.notify();
961
1003
  }
962
- async loadUserOrganisations() {
1004
+ /** Returns false if load should return early; when true, abort controller and loading state are set. */
1005
+ prepareLoad() {
963
1006
  if (!this.user || !this.session || !this.supabaseClient) {
964
1007
  this._selectedOrganisation = null;
965
1008
  this._organisations = [];
@@ -967,12 +1010,12 @@ var _OrganisationService = class _OrganisationService extends BaseService {
967
1010
  this._isLoading = false;
968
1011
  this._error = null;
969
1012
  this.notify();
970
- return;
1013
+ return false;
971
1014
  }
972
1015
  if (this.isLoadingRef) {
973
1016
  this._isLoading = true;
974
1017
  this.notify();
975
- return;
1018
+ return false;
976
1019
  }
977
1020
  const now = Date.now();
978
1021
  if (this._organisations.length > 0 && now - this.lastLoadTimeRef < 2e3) {
@@ -982,146 +1025,183 @@ var _OrganisationService = class _OrganisationService extends BaseService {
982
1025
  this._isLoading = true;
983
1026
  }
984
1027
  this.notify();
985
- return;
1028
+ return false;
986
1029
  }
987
1030
  if (this.abortControllerRef) {
988
1031
  this.abortControllerRef.abort();
989
1032
  }
990
1033
  this.abortControllerRef = new AbortController();
991
- const abortSignal = this.abortControllerRef.signal;
992
1034
  this.lastLoadTimeRef = now;
993
1035
  this.isLoadingRef = true;
994
1036
  this._isLoading = true;
995
1037
  this._error = null;
996
1038
  this.notify();
1039
+ return true;
1040
+ }
1041
+ async fetchRolesAndOrganisations(signal) {
1042
+ if (signal.aborted) {
1043
+ throw new Error("Request aborted");
1044
+ }
1045
+ if (!this.supabaseClient || !this.user) {
1046
+ throw new Error("Missing supabase client or user");
1047
+ }
997
1048
  try {
998
- let memberships, membershipError, organisations = [];
999
- try {
1000
- if (abortSignal.aborted) {
1001
- throw new Error("Request aborted");
1002
- }
1003
- const { data: rolesData, error: rolesError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
1049
+ const { data: rolesData, error: rolesError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
1050
+ id,
1051
+ user_id,
1052
+ organisation_id,
1053
+ role,
1054
+ status,
1055
+ granted_at,
1056
+ granted_by,
1057
+ revoked_at,
1058
+ revoked_by,
1059
+ notes,
1060
+ created_at,
1061
+ updated_at,
1062
+ core_organisations!inner(
1004
1063
  id,
1005
- user_id,
1006
- organisation_id,
1007
- role,
1008
- status,
1009
- granted_at,
1010
- granted_by,
1011
- revoked_at,
1012
- revoked_by,
1013
- notes,
1064
+ name,
1065
+ display_name,
1066
+ subscription_tier,
1067
+ settings,
1068
+ is_active,
1069
+ parent_id,
1014
1070
  created_at,
1015
- updated_at,
1016
- core_organisations!inner(
1017
- id,
1018
- name,
1019
- display_name,
1020
- subscription_tier,
1021
- settings,
1022
- is_active,
1023
- parent_id,
1024
- created_at,
1025
- updated_at
1026
- )
1027
- `).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null);
1028
- if (rolesError) {
1029
- logger.error("OrganisationService", "Error loading organisation roles:", rolesError);
1030
- throw rolesError;
1031
- }
1032
- memberships = rolesData?.map((m) => ({
1033
- ...m,
1034
- user_id: assertUserId(m.user_id),
1035
- organisation_id: assertOrganisationId(m.organisation_id)
1036
- })) || [];
1037
- const organisationsMap = /* @__PURE__ */ new Map();
1038
- rolesData?.forEach((role) => {
1039
- const roleWithOrg = role;
1040
- const orgData = roleWithOrg.core_organisations;
1041
- if (orgData && roleWithOrg.organisation_id && !organisationsMap.has(roleWithOrg.organisation_id)) {
1042
- organisationsMap.set(roleWithOrg.organisation_id, {
1043
- id: orgData.id,
1044
- name: orgData.name,
1045
- display_name: orgData.display_name,
1046
- subscription_tier: orgData.subscription_tier,
1047
- settings: orgData.settings,
1048
- is_active: orgData.is_active,
1049
- parent_id: orgData.parent_id,
1050
- created_at: orgData.created_at,
1051
- updated_at: orgData.updated_at
1052
- });
1053
- }
1054
- });
1055
- organisations = Array.from(organisationsMap.values());
1056
- } catch (queryError) {
1057
- if (queryError instanceof Error) {
1058
- membershipError = queryError;
1059
- } else if (queryError && typeof queryError === "object" && "message" in queryError) {
1060
- membershipError = new Error(String(queryError.message));
1061
- } else {
1062
- membershipError = new Error(String(queryError));
1071
+ updated_at
1072
+ )
1073
+ `).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null);
1074
+ if (rolesError) {
1075
+ logger.error("OrganisationService", "Error loading organisation roles:", rolesError);
1076
+ throw rolesError;
1077
+ }
1078
+ const memberships = rolesData?.map((m) => ({
1079
+ ...m,
1080
+ user_id: assertUserId(m.user_id),
1081
+ organisation_id: assertOrganisationId(m.organisation_id)
1082
+ })) || [];
1083
+ const organisationsMap = /* @__PURE__ */ new Map();
1084
+ rolesData?.forEach((role) => {
1085
+ const roleWithOrg = role;
1086
+ const orgData = roleWithOrg.core_organisations;
1087
+ if (orgData && roleWithOrg.organisation_id && !organisationsMap.has(roleWithOrg.organisation_id)) {
1088
+ organisationsMap.set(roleWithOrg.organisation_id, {
1089
+ id: orgData.id,
1090
+ name: orgData.name,
1091
+ display_name: orgData.display_name,
1092
+ subscription_tier: orgData.subscription_tier,
1093
+ settings: orgData.settings,
1094
+ is_active: orgData.is_active,
1095
+ parent_id: orgData.parent_id,
1096
+ created_at: orgData.created_at,
1097
+ updated_at: orgData.updated_at
1098
+ });
1063
1099
  }
1064
- logger.error("OrganisationService", "Error loading organisation roles:", membershipError);
1065
- throw membershipError;
1100
+ });
1101
+ const organisations = Array.from(organisationsMap.values());
1102
+ return { memberships, organisations };
1103
+ } catch (queryError) {
1104
+ const err2 = queryError instanceof Error ? queryError : queryError && typeof queryError === "object" && "message" in queryError ? new Error(String(queryError.message)) : new Error(String(queryError));
1105
+ logger.error("OrganisationService", "Error loading organisation roles:", err2);
1106
+ throw err2;
1107
+ }
1108
+ }
1109
+ async checkAndCacheSuperAdmin() {
1110
+ if (!this.user?.id) {
1111
+ this._isSuperAdmin = false;
1112
+ return false;
1113
+ }
1114
+ try {
1115
+ const { isSuperAdmin: checkSuperAdmin, isRBACInitialized: isRBACInitialized2, setupRBAC: setupRBAC2 } = await import('./api-BZR2CYXL.js');
1116
+ if (!isRBACInitialized2() && this.supabaseClient) {
1117
+ setupRBAC2(this.supabaseClient);
1066
1118
  }
1067
- let userIsSuperAdmin = false;
1068
- if (this.user?.id) {
1069
- try {
1070
- const { isSuperAdmin: checkSuperAdmin, isRBACInitialized: isRBACInitialized2, setupRBAC: setupRBAC2 } = await import('./api-F47QJ7FX.js');
1071
- if (!isRBACInitialized2() && this.supabaseClient) {
1072
- setupRBAC2(this.supabaseClient);
1073
- }
1074
- if (isRBACInitialized2()) {
1075
- userIsSuperAdmin = await checkSuperAdmin(this.user.id);
1119
+ if (isRBACInitialized2()) {
1120
+ const result = await checkSuperAdmin(this.user.id);
1121
+ const isSuper = result.ok && result.data;
1122
+ this._isSuperAdmin = isSuper;
1123
+ return isSuper;
1124
+ }
1125
+ this._isSuperAdmin = false;
1126
+ return false;
1127
+ } catch (error) {
1128
+ logger.warn("OrganisationService", "Failed to check super admin status", { error });
1129
+ this._isSuperAdmin = false;
1130
+ return false;
1131
+ }
1132
+ }
1133
+ applyEmptyStateAndNotify() {
1134
+ this._organisations = [];
1135
+ this._userMemberships = [];
1136
+ this._isLoading = false;
1137
+ this._error = null;
1138
+ this._isContextReady = true;
1139
+ this.notify();
1140
+ }
1141
+ selectInitialOrganisation(activeOrgs, memberships, organisations) {
1142
+ let initialOrg = null;
1143
+ try {
1144
+ const persistedOrgString = localStorage.getItem("pace-core-selected-organisation");
1145
+ if (persistedOrgString) {
1146
+ const persistedOrg = JSON.parse(persistedOrgString);
1147
+ if (persistedOrg.id && typeof persistedOrg.id === "string" && persistedOrg.id.trim() !== "") {
1148
+ const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
1149
+ if (validPersistedOrg) {
1150
+ initialOrg = validPersistedOrg;
1076
1151
  } else {
1077
- userIsSuperAdmin = false;
1152
+ localStorage.removeItem("pace-core-selected-organisation");
1078
1153
  }
1079
- this._isSuperAdmin = userIsSuperAdmin;
1080
- } catch (error) {
1081
- logger.warn("OrganisationService", "Failed to check super admin status", { error });
1082
- this._isSuperAdmin = false;
1154
+ } else {
1155
+ localStorage.removeItem("pace-core-selected-organisation");
1083
1156
  }
1084
- } else {
1085
- this._isSuperAdmin = false;
1086
1157
  }
1158
+ } catch {
1159
+ localStorage.removeItem("pace-core-selected-organisation");
1160
+ }
1161
+ if (!initialOrg) {
1162
+ const adminMembership = memberships.find((m) => m.role === "org_admin");
1163
+ if (adminMembership) {
1164
+ const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
1165
+ if (foundOrg) initialOrg = foundOrg;
1166
+ }
1167
+ }
1168
+ if (!initialOrg) {
1169
+ initialOrg = activeOrgs[0];
1170
+ }
1171
+ if (!initialOrg) {
1172
+ throw new Error("No valid organisation found for user");
1173
+ }
1174
+ localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
1175
+ return initialOrg;
1176
+ }
1177
+ async loadUserOrganisations() {
1178
+ if (!this.prepareLoad()) return;
1179
+ const abortSignal = this.abortControllerRef.signal;
1180
+ try {
1181
+ const { memberships, organisations } = await this.fetchRolesAndOrganisations(abortSignal);
1182
+ const userIsSuperAdmin = await this.checkAndCacheSuperAdmin();
1087
1183
  if (!memberships || memberships.length === 0) {
1088
1184
  if (userIsSuperAdmin) {
1089
- this._organisations = [];
1090
- this._userMemberships = [];
1091
- this._isLoading = false;
1092
- this._error = null;
1093
- this._isContextReady = true;
1094
- this.notify();
1185
+ this.applyEmptyStateAndNotify();
1095
1186
  return;
1096
1187
  }
1097
1188
  throw new Error("User has no active organisation memberships");
1098
1189
  }
1099
1190
  if (!organisations || organisations.length === 0) {
1100
1191
  if (userIsSuperAdmin) {
1101
- this._organisations = [];
1102
- this._userMemberships = [];
1103
- this._isLoading = false;
1104
- this._error = null;
1105
- this._isContextReady = true;
1106
- this.notify();
1192
+ this.applyEmptyStateAndNotify();
1107
1193
  return;
1108
1194
  }
1109
1195
  throw new Error("No organisations found in role data");
1110
1196
  }
1111
1197
  const roleMap = /* @__PURE__ */ new Map();
1112
- memberships?.forEach((membership) => {
1198
+ memberships.forEach((membership) => {
1113
1199
  roleMap.set(membership.organisation_id, membership.role);
1114
1200
  });
1115
- const orgs = organisations;
1116
- const activeOrgs = orgs.filter((org) => org.is_active);
1201
+ const activeOrgs = organisations.filter((org) => org.is_active);
1117
1202
  if (activeOrgs.length === 0) {
1118
1203
  if (userIsSuperAdmin) {
1119
- this._organisations = [];
1120
- this._userMemberships = [];
1121
- this._isLoading = false;
1122
- this._error = null;
1123
- this._isContextReady = true;
1124
- this.notify();
1204
+ this.applyEmptyStateAndNotify();
1125
1205
  return;
1126
1206
  }
1127
1207
  throw new Error("User has no access to active organisations");
@@ -1134,44 +1214,7 @@ var _OrganisationService = class _OrganisationService extends BaseService {
1134
1214
  this._organisations = sortedOrgs;
1135
1215
  this._userMemberships = memberships;
1136
1216
  this._roleMapState = roleMap;
1137
- let initialOrg = null;
1138
- let _selectionMethod = "first";
1139
- try {
1140
- const persistedOrgString = localStorage.getItem("pace-core-selected-organisation");
1141
- if (persistedOrgString) {
1142
- const persistedOrg = JSON.parse(persistedOrgString);
1143
- if (persistedOrg.id && typeof persistedOrg.id === "string" && persistedOrg.id.trim() !== "") {
1144
- const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
1145
- if (validPersistedOrg) {
1146
- initialOrg = validPersistedOrg;
1147
- _selectionMethod = "persisted";
1148
- } else {
1149
- localStorage.removeItem("pace-core-selected-organisation");
1150
- }
1151
- } else {
1152
- localStorage.removeItem("pace-core-selected-organisation");
1153
- }
1154
- }
1155
- } catch (_storageError) {
1156
- localStorage.removeItem("pace-core-selected-organisation");
1157
- }
1158
- if (!initialOrg) {
1159
- const adminMembership = memberships.find((m) => m.role === "org_admin");
1160
- if (adminMembership) {
1161
- const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
1162
- if (foundOrg) {
1163
- initialOrg = foundOrg;
1164
- _selectionMethod = "admin";
1165
- }
1166
- }
1167
- }
1168
- if (!initialOrg) {
1169
- initialOrg = activeOrgs[0];
1170
- _selectionMethod = "first";
1171
- }
1172
- if (!initialOrg) {
1173
- throw new Error("No valid organisation found for user");
1174
- }
1217
+ const initialOrg = this.selectInitialOrganisation(activeOrgs, memberships, organisations);
1175
1218
  const currentSelectedOrg = this._selectedOrganisation;
1176
1219
  if (currentSelectedOrg && !activeOrgs.some((org) => org.id === currentSelectedOrg.id)) {
1177
1220
  logger.warn("OrganisationService", "Current selected organisation is no longer valid, resetting", {
@@ -1181,14 +1224,13 @@ var _OrganisationService = class _OrganisationService extends BaseService {
1181
1224
  this._selectedOrganisation = null;
1182
1225
  }
1183
1226
  this._selectedOrganisation = initialOrg;
1184
- localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
1185
1227
  await this.setDatabaseOrganisationContext(initialOrg);
1186
1228
  this.retryCount = 0;
1187
1229
  this.hasFailedRef = false;
1188
- } catch (err) {
1189
- const error = err;
1230
+ } catch (err2) {
1231
+ const error = err2;
1190
1232
  if (error.message !== "User has no access to active organisations") {
1191
- logger.error("OrganisationService", "Failed to load organisations:", err);
1233
+ logger.error("OrganisationService", "Failed to load organisations:", err2);
1192
1234
  }
1193
1235
  this._error = error;
1194
1236
  this.retryCount = this.retryCount + 1;
@@ -1215,7 +1257,6 @@ var _OrganisationService = class _OrganisationService extends BaseService {
1215
1257
  };
1216
1258
  _OrganisationService.instanceCount = 0;
1217
1259
  var OrganisationService = _OrganisationService;
1218
- var OrganisationServiceContext = createContext(null);
1219
1260
  function OrganisationServiceProvider({
1220
1261
  children,
1221
1262
  supabaseClient,
@@ -1303,86 +1344,100 @@ var _EventService = class _EventService extends BaseService {
1303
1344
  const newOrgId = selectedOrganisation?.id;
1304
1345
  const previousUserId = this.user?.id || null;
1305
1346
  const newUserId = user?.id || null;
1306
- this.appName;
1307
- if (previousUserId !== newUserId) {
1308
- if (previousUserId !== null) {
1309
- await this.clearEventSelectionForUser(previousUserId);
1310
- }
1311
- if (newUserId === null) {
1312
- this.selectedEvent = null;
1313
- this.setSelectedEventId?.(null);
1314
- }
1315
- this.resetInitialization();
1316
- this.isInitializedRef = false;
1317
- this.isFetchingRef = false;
1318
- this.userClearedEventRef = false;
1319
- this.hasAutoSelectedRef = false;
1347
+ await this.handleUserChange(previousUserId, newUserId);
1348
+ this.applyNewDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
1349
+ await this.updateSuperAdminStatus(user);
1350
+ this.handleOrganisationChange(previousOrgId, newOrgId);
1351
+ this.notify();
1352
+ }
1353
+ async handleUserChange(previousUserId, newUserId) {
1354
+ if (previousUserId === newUserId) {
1355
+ return;
1356
+ }
1357
+ if (previousUserId !== null) {
1358
+ await this.clearEventSelectionForUser(previousUserId);
1359
+ }
1360
+ if (newUserId === null) {
1361
+ this.selectedEvent = null;
1362
+ this.setSelectedEventId?.(null);
1320
1363
  }
1364
+ this.resetInitialization();
1365
+ this.isInitializedRef = false;
1366
+ this.isFetchingRef = false;
1367
+ this.userClearedEventRef = false;
1368
+ this.hasAutoSelectedRef = false;
1369
+ }
1370
+ applyNewDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
1321
1371
  this.supabaseClient = supabaseClient;
1322
1372
  this.user = user;
1323
1373
  this.session = session;
1324
1374
  this.appName = appName;
1325
1375
  this.selectedOrganisation = selectedOrganisation;
1326
1376
  this.setSelectedEventId = setSelectedEventId;
1327
- if (user?.id) {
1328
- try {
1329
- const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-F47QJ7FX.js');
1330
- if (!isRBACInitialized2() && this.supabaseClient) {
1331
- setupRBAC2(this.supabaseClient);
1332
- }
1333
- if (isRBACInitialized2()) {
1334
- this.isSuperAdmin = await checkSuperAdmin(user.id);
1335
- } else {
1336
- logger.warn("EventService", "RBAC not initialized in updateDependencies, keeping existing super admin status", {
1337
- userId: user.id,
1338
- existingIsSuperAdmin: this.isSuperAdmin,
1339
- note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1340
- });
1341
- }
1342
- } catch (error) {
1343
- logger.warn("EventService", "Failed to check super admin status in updateDependencies", {
1344
- error,
1377
+ }
1378
+ async updateSuperAdminStatus(user) {
1379
+ if (!user?.id) {
1380
+ this.isSuperAdmin = false;
1381
+ return;
1382
+ }
1383
+ try {
1384
+ const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-BZR2CYXL.js');
1385
+ if (!isRBACInitialized2() && this.supabaseClient) {
1386
+ setupRBAC2(this.supabaseClient);
1387
+ }
1388
+ if (isRBACInitialized2()) {
1389
+ const result = await checkSuperAdmin(user.id);
1390
+ this.isSuperAdmin = result.ok && result.data;
1391
+ } else {
1392
+ logger.warn("EventService", "RBAC not initialized in updateDependencies, keeping existing super admin status", {
1345
1393
  userId: user.id,
1346
- existingIsSuperAdmin: this.isSuperAdmin
1394
+ existingIsSuperAdmin: this.isSuperAdmin,
1395
+ note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1347
1396
  });
1348
1397
  }
1349
- } else {
1350
- this.isSuperAdmin = false;
1398
+ } catch (error) {
1399
+ logger.warn("EventService", "Failed to check super admin status in updateDependencies", {
1400
+ error,
1401
+ userId: user.id,
1402
+ existingIsSuperAdmin: this.isSuperAdmin
1403
+ });
1351
1404
  }
1352
- if (previousOrgId !== newOrgId) {
1353
- this.resetInitialization();
1354
- this.isInitializedRef = false;
1355
- this.isFetchingRef = false;
1356
- const shouldClearEvents = !this.isSuperAdmin;
1357
- const isFirstOrgSet = (previousOrgId === null || previousOrgId === void 0) && newOrgId !== null && newOrgId !== void 0;
1358
- if (isFirstOrgSet) {
1359
- const hadAutoSelectedEvent = this.hasAutoSelectedRef && !!this.selectedEvent;
1360
- this.userClearedEventRef = false;
1361
- if (!hadAutoSelectedEvent) {
1362
- this.hasAutoSelectedRef = false;
1363
- }
1364
- logger.debug("EventService", "Organisation first set - preserving event and resetting auto-selection flags", {
1365
- organisationId: newOrgId,
1366
- hasSelectedEvent: !!this.selectedEvent,
1367
- selectedEventId: this.selectedEvent?.event_id,
1368
- hadAutoSelectedEvent,
1369
- preservingEvent: hadAutoSelectedEvent,
1370
- previousOrgId,
1371
- newOrgId
1372
- });
1373
- } else if (previousOrgId !== null && previousOrgId !== void 0 && newOrgId !== null && newOrgId !== void 0 && previousOrgId !== newOrgId) {
1374
- if (shouldClearEvents) {
1375
- this.events = [];
1376
- this.setSelectedEvent(null);
1377
- }
1378
- } else if (previousOrgId !== null && previousOrgId !== void 0 && newOrgId === null) {
1379
- if (shouldClearEvents) {
1380
- this.events = [];
1381
- this.setSelectedEvent(null);
1382
- }
1405
+ }
1406
+ handleOrganisationChange(previousOrgId, newOrgId) {
1407
+ if (previousOrgId === newOrgId) {
1408
+ return;
1409
+ }
1410
+ this.resetInitialization();
1411
+ this.isInitializedRef = false;
1412
+ this.isFetchingRef = false;
1413
+ const shouldClearEvents = !this.isSuperAdmin;
1414
+ const isFirstOrgSet = (previousOrgId === null || previousOrgId === void 0) && newOrgId !== null && newOrgId !== void 0;
1415
+ if (isFirstOrgSet) {
1416
+ const hadAutoSelectedEvent = this.hasAutoSelectedRef && !!this.selectedEvent;
1417
+ this.userClearedEventRef = false;
1418
+ if (!hadAutoSelectedEvent) {
1419
+ this.hasAutoSelectedRef = false;
1383
1420
  }
1421
+ logger.debug("EventService", "Organisation first set - preserving event and resetting auto-selection flags", {
1422
+ organisationId: newOrgId,
1423
+ hasSelectedEvent: !!this.selectedEvent,
1424
+ selectedEventId: this.selectedEvent?.event_id,
1425
+ hadAutoSelectedEvent,
1426
+ preservingEvent: hadAutoSelectedEvent,
1427
+ previousOrgId,
1428
+ newOrgId
1429
+ });
1430
+ return;
1431
+ }
1432
+ const switchingOrgs = previousOrgId != null && newOrgId != null && previousOrgId !== newOrgId;
1433
+ const orgRemoved = previousOrgId != null && newOrgId === null;
1434
+ if (switchingOrgs && shouldClearEvents) {
1435
+ this.events = [];
1436
+ this.setSelectedEvent(null);
1437
+ } else if (orgRemoved && shouldClearEvents) {
1438
+ this.events = [];
1439
+ this.setSelectedEvent(null);
1384
1440
  }
1385
- this.notify();
1386
1441
  }
1387
1442
  // Event state getters
1388
1443
  getEvents() {
@@ -1524,6 +1579,122 @@ var _EventService = class _EventService extends BaseService {
1524
1579
  }
1525
1580
  doCleanup() {
1526
1581
  }
1582
+ async resolveOrganisationIdForRpc() {
1583
+ let userIsSuperAdmin = this.isSuperAdmin;
1584
+ try {
1585
+ const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-BZR2CYXL.js');
1586
+ if (!isRBACInitialized2() && this.supabaseClient) {
1587
+ setupRBAC2(this.supabaseClient);
1588
+ }
1589
+ if (isRBACInitialized2()) {
1590
+ const result = await checkSuperAdmin(this.user.id);
1591
+ userIsSuperAdmin = result.ok && result.data;
1592
+ this.isSuperAdmin = userIsSuperAdmin;
1593
+ } else {
1594
+ if (this.isSuperAdmin) {
1595
+ userIsSuperAdmin = true;
1596
+ logger.warn("EventService", "RBAC not initialized, using cached super admin status", {
1597
+ userId: this.user.id,
1598
+ cachedIsSuperAdmin: this.isSuperAdmin,
1599
+ note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1600
+ });
1601
+ } else {
1602
+ logger.warn("EventService", "RBAC not initialized, using cached non-super-admin status", {
1603
+ userId: this.user.id,
1604
+ cachedIsSuperAdmin: this.isSuperAdmin,
1605
+ note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1606
+ });
1607
+ }
1608
+ }
1609
+ if (userIsSuperAdmin) {
1610
+ return null;
1611
+ }
1612
+ if (this.selectedEvent) {
1613
+ return this.selectedEvent.organisation_id;
1614
+ }
1615
+ if (this.selectedOrganisation) {
1616
+ return this.selectedOrganisation.id;
1617
+ }
1618
+ return null;
1619
+ } catch (superAdminCheckError) {
1620
+ if (this.isSuperAdmin) {
1621
+ logger.warn("EventService", "Super admin check failed, using cached super admin status", {
1622
+ error: superAdminCheckError,
1623
+ cachedIsSuperAdmin: this.isSuperAdmin
1624
+ });
1625
+ return null;
1626
+ }
1627
+ logger.warn("EventService", "Failed to check super admin status, using organisation-scoped query", {
1628
+ error: superAdminCheckError,
1629
+ cachedIsSuperAdmin: this.isSuperAdmin
1630
+ });
1631
+ if (this.selectedEvent) {
1632
+ return this.selectedEvent.organisation_id;
1633
+ }
1634
+ if (this.selectedOrganisation) {
1635
+ return this.selectedOrganisation.id;
1636
+ }
1637
+ return null;
1638
+ }
1639
+ }
1640
+ transformRpcDataToEvents(data) {
1641
+ const eventsData = Array.isArray(data) ? data : [];
1642
+ const transformed = eventsData.map((event) => ({
1643
+ id: event.event_id,
1644
+ event_id: event.event_id,
1645
+ event_name: event.event_name,
1646
+ event_code: event.event_code,
1647
+ event_date: event.event_date ?? void 0,
1648
+ event_venue: event.event_venue ?? void 0,
1649
+ event_participants: event.event_participants ?? void 0,
1650
+ event_colours: event.event_colours,
1651
+ event_logo: "",
1652
+ organisation_id: assertOrganisationId(event.organisation_id),
1653
+ is_visible: event.is_visible,
1654
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
1655
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1656
+ }));
1657
+ return [...transformed].sort((a, b) => {
1658
+ if (a.event_date && b.event_date) {
1659
+ return new Date(b.event_date).getTime() - new Date(a.event_date).getTime();
1660
+ }
1661
+ if (a.event_date && !b.event_date) return -1;
1662
+ if (!a.event_date && b.event_date) return 1;
1663
+ return 0;
1664
+ });
1665
+ }
1666
+ validateSelectedEventInList(events) {
1667
+ if (!this.selectedEvent) {
1668
+ return;
1669
+ }
1670
+ const selectedEventId = this.selectedEvent.event_id;
1671
+ const eventStillExists = events.some((e) => e.event_id === selectedEventId);
1672
+ if (!eventStillExists) {
1673
+ const previousUserClearedRef = this.userClearedEventRef;
1674
+ this.selectedEvent = null;
1675
+ this.setSelectedEventId?.(null);
1676
+ this.userClearedEventRef = previousUserClearedRef;
1677
+ }
1678
+ }
1679
+ async runPersistedOrAutoSelection(events, skipLoadPersisted) {
1680
+ this.hasAutoSelectedRef = false;
1681
+ if (!skipLoadPersisted) {
1682
+ const persistedEventLoaded = await this.loadPersistedEvent(events);
1683
+ if (!persistedEventLoaded && !this.userClearedEventRef) {
1684
+ const nextEvent = this.getNextEventByDate(events);
1685
+ if (nextEvent) {
1686
+ this.hasAutoSelectedRef = true;
1687
+ this.setSelectedEvent(nextEvent);
1688
+ }
1689
+ }
1690
+ } else if (!this.userClearedEventRef) {
1691
+ const nextEvent = this.getNextEventByDate(events);
1692
+ if (nextEvent) {
1693
+ this.hasAutoSelectedRef = true;
1694
+ this.setSelectedEvent(nextEvent);
1695
+ }
1696
+ }
1697
+ }
1527
1698
  async fetchEvents(skipLoadPersisted = false) {
1528
1699
  if (!this.user || !this.session || !this.supabaseClient || !this.appName) {
1529
1700
  this.notify();
@@ -1537,65 +1708,7 @@ var _EventService = class _EventService extends BaseService {
1537
1708
  this.isFetchingRef = true;
1538
1709
  const isMounted = true;
1539
1710
  try {
1540
- let organisationIdForRpc = null;
1541
- let userIsSuperAdmin = this.isSuperAdmin;
1542
- try {
1543
- const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-F47QJ7FX.js');
1544
- if (!isRBACInitialized2() && this.supabaseClient) {
1545
- setupRBAC2(this.supabaseClient);
1546
- }
1547
- if (isRBACInitialized2()) {
1548
- userIsSuperAdmin = await checkSuperAdmin(this.user.id);
1549
- this.isSuperAdmin = userIsSuperAdmin;
1550
- } else {
1551
- if (this.isSuperAdmin) {
1552
- userIsSuperAdmin = true;
1553
- logger.warn("EventService", "RBAC not initialized, using cached super admin status", {
1554
- userId: this.user.id,
1555
- cachedIsSuperAdmin: this.isSuperAdmin,
1556
- note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1557
- });
1558
- } else {
1559
- logger.warn("EventService", "RBAC not initialized, using cached non-super-admin status", {
1560
- userId: this.user.id,
1561
- cachedIsSuperAdmin: this.isSuperAdmin,
1562
- note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1563
- });
1564
- }
1565
- }
1566
- if (userIsSuperAdmin) {
1567
- organisationIdForRpc = null;
1568
- } else {
1569
- if (this.selectedEvent) {
1570
- organisationIdForRpc = this.selectedEvent.organisation_id;
1571
- } else if (this.selectedOrganisation) {
1572
- organisationIdForRpc = this.selectedOrganisation.id;
1573
- } else {
1574
- organisationIdForRpc = null;
1575
- }
1576
- }
1577
- } catch (superAdminCheckError) {
1578
- if (this.isSuperAdmin) {
1579
- userIsSuperAdmin = true;
1580
- organisationIdForRpc = null;
1581
- logger.warn("EventService", "Super admin check failed, using cached super admin status", {
1582
- error: superAdminCheckError,
1583
- cachedIsSuperAdmin: this.isSuperAdmin
1584
- });
1585
- } else {
1586
- logger.warn("EventService", "Failed to check super admin status, using organisation-scoped query", {
1587
- error: superAdminCheckError,
1588
- cachedIsSuperAdmin: this.isSuperAdmin
1589
- });
1590
- if (this.selectedEvent) {
1591
- organisationIdForRpc = this.selectedEvent.organisation_id;
1592
- } else if (this.selectedOrganisation) {
1593
- organisationIdForRpc = this.selectedOrganisation.id;
1594
- } else {
1595
- organisationIdForRpc = null;
1596
- }
1597
- }
1598
- }
1711
+ const organisationIdForRpc = await this.resolveOrganisationIdForRpc();
1599
1712
  const { data, error: rpcError } = await this.supabaseClient.rpc("data_user_events_get", {
1600
1713
  p_user_id: this.user.id,
1601
1714
  p_organisation_id: organisationIdForRpc,
@@ -1606,71 +1719,15 @@ var _EventService = class _EventService extends BaseService {
1606
1719
  throw new Error(rpcError.message || "Failed to fetch events");
1607
1720
  }
1608
1721
  if (isMounted) {
1609
- const eventsData = data || [];
1610
- const transformedEvents = eventsData.map((event) => ({
1611
- id: event.event_id,
1612
- event_id: event.event_id,
1613
- event_name: event.event_name,
1614
- event_code: event.event_code,
1615
- event_date: event.event_date,
1616
- event_venue: event.event_venue,
1617
- event_participants: event.event_participants,
1618
- event_colours: event.event_colours,
1619
- event_logo: "",
1620
- // No logo field in event table
1621
- organisation_id: assertOrganisationId(event.organisation_id),
1622
- is_visible: event.is_visible,
1623
- created_at: (/* @__PURE__ */ new Date()).toISOString(),
1624
- updated_at: (/* @__PURE__ */ new Date()).toISOString()
1625
- }));
1626
- const sortedEvents = [...transformedEvents].sort((a, b) => {
1627
- if (a.event_date && b.event_date) {
1628
- return new Date(b.event_date).getTime() - new Date(a.event_date).getTime();
1629
- }
1630
- if (a.event_date && !b.event_date) return -1;
1631
- if (!a.event_date && b.event_date) return 1;
1632
- return 0;
1633
- });
1634
- this.events = sortedEvents;
1722
+ const transformedEvents = this.transformRpcDataToEvents(data ?? []);
1723
+ this.events = transformedEvents;
1635
1724
  this.error = null;
1636
- if (this.selectedEvent) {
1637
- const selectedEventId = this.selectedEvent.event_id;
1638
- const eventStillExists = transformedEvents.some(
1639
- (e) => e.event_id === selectedEventId
1640
- );
1641
- if (!eventStillExists) {
1642
- const previousUserClearedRef = this.userClearedEventRef;
1643
- this.selectedEvent = null;
1644
- this.setSelectedEventId?.(null);
1645
- this.userClearedEventRef = previousUserClearedRef;
1646
- }
1647
- }
1648
- this.hasAutoSelectedRef = false;
1649
- if (!skipLoadPersisted) {
1650
- const persistedEventLoaded = await this.loadPersistedEvent(transformedEvents);
1651
- if (!persistedEventLoaded && !this.userClearedEventRef) {
1652
- const nextEvent = this.getNextEventByDate(transformedEvents);
1653
- if (nextEvent) {
1654
- this.hasAutoSelectedRef = true;
1655
- this.setSelectedEvent(nextEvent);
1656
- }
1657
- } else if (persistedEventLoaded) {
1658
- } else if (this.userClearedEventRef) {
1659
- }
1660
- } else {
1661
- if (!this.userClearedEventRef) {
1662
- const nextEvent = this.getNextEventByDate(transformedEvents);
1663
- if (nextEvent) {
1664
- this.hasAutoSelectedRef = true;
1665
- this.setSelectedEvent(nextEvent);
1666
- }
1667
- } else {
1668
- }
1669
- }
1725
+ this.validateSelectedEventInList(transformedEvents);
1726
+ await this.runPersistedOrAutoSelection(transformedEvents, skipLoadPersisted);
1670
1727
  }
1671
- } catch (err) {
1672
- logger.error("EventService", "Error fetching events:", err);
1673
- const _error = err instanceof Error ? err : new Error("Unknown error occurred");
1728
+ } catch (err2) {
1729
+ logger.error("EventService", "Error fetching events:", err2);
1730
+ const _error = err2 instanceof Error ? err2 : new Error("Unknown error occurred");
1674
1731
  {
1675
1732
  this.error = _error;
1676
1733
  this.events = [];
@@ -1782,6 +1839,7 @@ function EventServiceProvider({
1782
1839
  }), [eventService]);
1783
1840
  return /* @__PURE__ */ jsx(EventServiceContext.Provider, { value: contextValue, children });
1784
1841
  }
1842
+ var InactivityServiceContext = createContext(null);
1785
1843
 
1786
1844
  // src/services/InactivityService.ts
1787
1845
  var InactivityService = class extends BaseService {
@@ -2005,163 +2063,157 @@ var InactivityService = class extends BaseService {
2005
2063
  }
2006
2064
  this.setupEventHandlers();
2007
2065
  }
2008
- setupEventHandlers() {
2009
- if (typeof window === "undefined") return;
2010
- let warningTimer = null;
2011
- let logoutTimer = null;
2012
- let countdownInterval = null;
2013
- let lastActivity = Date.now();
2014
- let prevIsIdle = false;
2015
- let prevShowWarning = false;
2016
- let prevShowInactivityWarning = false;
2017
- let prevInactivityTimeRemaining = 0;
2018
- let prevTimeRemaining = this.idleTimeoutMs;
2019
- const getTimeUntilWarning = () => {
2020
- const timeSinceActivity = Date.now() - lastActivity;
2021
- return Math.max(0, this.idleTimeoutMs - this.warnBeforeMs - timeSinceActivity);
2022
- };
2023
- const getTimeUntilLogout = () => {
2024
- const timeSinceActivity = Date.now() - lastActivity;
2025
- return Math.max(0, this.idleTimeoutMs - timeSinceActivity);
2026
- };
2027
- const updateState = (forceNotify = false) => {
2028
- const now = Date.now();
2029
- const timeSinceActivity = now - lastActivity;
2030
- const timeUntilIdle = this.idleTimeoutMs - timeSinceActivity;
2031
- const newIsIdle = timeSinceActivity >= this.idleTimeoutMs;
2032
- const newShowWarning = timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs && !newIsIdle;
2033
- const newShowInactivityWarning = newShowWarning;
2034
- const newInactivityTimeRemaining = newShowWarning ? Math.ceil(timeUntilIdle / 1e3) : 0;
2035
- const newTimeRemaining = Math.max(0, timeUntilIdle);
2036
- const stateChanged = prevIsIdle !== newIsIdle || prevShowWarning !== newShowWarning || prevShowInactivityWarning !== newShowInactivityWarning || newShowWarning && prevInactivityTimeRemaining !== newInactivityTimeRemaining || prevTimeRemaining !== newTimeRemaining;
2037
- if (stateChanged || forceNotify) {
2038
- this._isIdle = newIsIdle;
2039
- this._showWarning = newShowWarning;
2040
- this._showInactivityWarning = newShowInactivityWarning;
2041
- this._inactivityTimeRemaining = newInactivityTimeRemaining;
2042
- this._timeRemaining = newTimeRemaining;
2043
- prevIsIdle = newIsIdle;
2044
- prevShowWarning = newShowWarning;
2045
- prevShowInactivityWarning = newShowInactivityWarning;
2046
- prevInactivityTimeRemaining = newInactivityTimeRemaining;
2047
- prevTimeRemaining = newTimeRemaining;
2048
- if (stateChanged) {
2049
- this.notify();
2050
- }
2051
- if (newIsIdle) {
2052
- this.handleIdleLogout();
2053
- }
2066
+ runUpdateState(ctx, forceNotify = false) {
2067
+ const now = Date.now();
2068
+ const timeSinceActivity = now - ctx.lastActivity;
2069
+ const timeUntilIdle = this.idleTimeoutMs - timeSinceActivity;
2070
+ const newIsIdle = timeSinceActivity >= this.idleTimeoutMs;
2071
+ const newShowWarning = timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs && !newIsIdle;
2072
+ const newShowInactivityWarning = newShowWarning;
2073
+ const newInactivityTimeRemaining = newShowWarning ? Math.ceil(timeUntilIdle / 1e3) : 0;
2074
+ const newTimeRemaining = Math.max(0, timeUntilIdle);
2075
+ const stateChanged = ctx.prevIsIdle !== newIsIdle || ctx.prevShowWarning !== newShowWarning || ctx.prevShowInactivityWarning !== newShowInactivityWarning || newShowWarning && ctx.prevInactivityTimeRemaining !== newInactivityTimeRemaining || ctx.prevTimeRemaining !== newTimeRemaining;
2076
+ if (stateChanged || forceNotify) {
2077
+ this._isIdle = newIsIdle;
2078
+ this._showWarning = newShowWarning;
2079
+ this._showInactivityWarning = newShowInactivityWarning;
2080
+ this._inactivityTimeRemaining = newInactivityTimeRemaining;
2081
+ this._timeRemaining = newTimeRemaining;
2082
+ ctx.prevIsIdle = newIsIdle;
2083
+ ctx.prevShowWarning = newShowWarning;
2084
+ ctx.prevShowInactivityWarning = newShowInactivityWarning;
2085
+ ctx.prevInactivityTimeRemaining = newInactivityTimeRemaining;
2086
+ ctx.prevTimeRemaining = newTimeRemaining;
2087
+ if (stateChanged) {
2088
+ this.notify();
2054
2089
  }
2055
- };
2056
- const scheduleNextCheck = () => {
2057
- if (warningTimer) {
2058
- clearTimeout(warningTimer);
2059
- warningTimer = null;
2060
- }
2061
- if (logoutTimer) {
2062
- clearTimeout(logoutTimer);
2063
- logoutTimer = null;
2064
- }
2065
- if (countdownInterval) {
2066
- clearInterval(countdownInterval);
2067
- countdownInterval = null;
2068
- }
2069
- const timeUntilWarning = getTimeUntilWarning();
2070
- const timeUntilLogout = getTimeUntilLogout();
2071
- const timeSinceActivity = Date.now() - lastActivity;
2072
- if (timeSinceActivity >= this.idleTimeoutMs) {
2073
- return;
2074
- }
2075
- if (timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs) {
2076
- updateState();
2077
- countdownInterval = setInterval(() => {
2078
- updateState();
2079
- if (Date.now() - lastActivity >= this.idleTimeoutMs) {
2080
- if (countdownInterval) {
2081
- clearInterval(countdownInterval);
2082
- countdownInterval = null;
2083
- }
2084
- this.handleIdleLogout();
2085
- }
2086
- }, 1e3);
2087
- logoutTimer = setTimeout(() => {
2088
- if (countdownInterval) {
2089
- clearInterval(countdownInterval);
2090
- countdownInterval = null;
2090
+ if (newIsIdle) {
2091
+ this.handleIdleLogout();
2092
+ }
2093
+ }
2094
+ }
2095
+ runScheduleNextCheck(ctx) {
2096
+ if (ctx.warningTimer) {
2097
+ clearTimeout(ctx.warningTimer);
2098
+ ctx.warningTimer = null;
2099
+ }
2100
+ if (ctx.logoutTimer) {
2101
+ clearTimeout(ctx.logoutTimer);
2102
+ ctx.logoutTimer = null;
2103
+ }
2104
+ if (ctx.countdownInterval) {
2105
+ clearInterval(ctx.countdownInterval);
2106
+ ctx.countdownInterval = null;
2107
+ }
2108
+ const getTimeUntilWarning = () => Math.max(0, this.idleTimeoutMs - this.warnBeforeMs - (Date.now() - ctx.lastActivity));
2109
+ const getTimeUntilLogout = () => Math.max(0, this.idleTimeoutMs - (Date.now() - ctx.lastActivity));
2110
+ const timeUntilWarning = getTimeUntilWarning();
2111
+ const timeUntilLogout = getTimeUntilLogout();
2112
+ const timeSinceActivity = Date.now() - ctx.lastActivity;
2113
+ if (timeSinceActivity >= this.idleTimeoutMs) {
2114
+ return;
2115
+ }
2116
+ if (timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs) {
2117
+ this.runUpdateState(ctx);
2118
+ ctx.countdownInterval = setInterval(() => {
2119
+ this.runUpdateState(ctx);
2120
+ if (Date.now() - ctx.lastActivity >= this.idleTimeoutMs) {
2121
+ if (ctx.countdownInterval) {
2122
+ clearInterval(ctx.countdownInterval);
2123
+ ctx.countdownInterval = null;
2091
2124
  }
2092
2125
  this.handleIdleLogout();
2093
- }, timeUntilLogout);
2094
- } else {
2095
- const timeUntilWarningMs = timeUntilWarning;
2096
- const adaptiveInterval = timeUntilWarningMs > 5 * 60 * 1e3 ? 60 * 1e3 : timeUntilWarningMs > 60 * 1e3 ? 10 * 1e3 : 1e3;
2097
- warningTimer = setTimeout(() => {
2098
- updateState();
2099
- scheduleNextCheck();
2100
- }, Math.min(adaptiveInterval, timeUntilWarningMs));
2101
- }
2102
- };
2103
- const resetTimers = () => {
2104
- lastActivity = Date.now();
2105
- if (warningTimer) {
2106
- clearTimeout(warningTimer);
2107
- warningTimer = null;
2108
- }
2109
- if (logoutTimer) {
2110
- clearTimeout(logoutTimer);
2111
- logoutTimer = null;
2112
- }
2113
- if (countdownInterval) {
2114
- clearInterval(countdownInterval);
2115
- countdownInterval = null;
2116
- }
2117
- const hadWarning = this._showWarning || this._showInactivityWarning;
2118
- this._showInactivityWarning = false;
2119
- this._inactivityTimeRemaining = 0;
2120
- this._isIdle = false;
2121
- this._showWarning = false;
2122
- this._timeRemaining = this.idleTimeoutMs;
2123
- prevIsIdle = false;
2124
- prevShowWarning = false;
2125
- prevShowInactivityWarning = false;
2126
- prevInactivityTimeRemaining = 0;
2127
- prevTimeRemaining = this.idleTimeoutMs;
2128
- if (hadWarning) {
2129
- this.notify();
2130
- }
2131
- scheduleNextCheck();
2126
+ }
2127
+ }, 1e3);
2128
+ ctx.logoutTimer = setTimeout(() => {
2129
+ if (ctx.countdownInterval) {
2130
+ clearInterval(ctx.countdownInterval);
2131
+ ctx.countdownInterval = null;
2132
+ }
2133
+ this.handleIdleLogout();
2134
+ }, timeUntilLogout);
2135
+ } else {
2136
+ const timeUntilWarningMs = timeUntilWarning;
2137
+ const adaptiveInterval = timeUntilWarningMs > 5 * 60 * 1e3 ? 60 * 1e3 : timeUntilWarningMs > 60 * 1e3 ? 10 * 1e3 : 1e3;
2138
+ ctx.warningTimer = setTimeout(() => {
2139
+ this.runUpdateState(ctx);
2140
+ this.runScheduleNextCheck(ctx);
2141
+ }, Math.min(adaptiveInterval, timeUntilWarningMs));
2142
+ }
2143
+ }
2144
+ runResetTimers(ctx) {
2145
+ ctx.lastActivity = Date.now();
2146
+ if (ctx.warningTimer) {
2147
+ clearTimeout(ctx.warningTimer);
2148
+ ctx.warningTimer = null;
2149
+ }
2150
+ if (ctx.logoutTimer) {
2151
+ clearTimeout(ctx.logoutTimer);
2152
+ ctx.logoutTimer = null;
2153
+ }
2154
+ if (ctx.countdownInterval) {
2155
+ clearInterval(ctx.countdownInterval);
2156
+ ctx.countdownInterval = null;
2157
+ }
2158
+ const hadWarning = this._showWarning || this._showInactivityWarning;
2159
+ this._showInactivityWarning = false;
2160
+ this._inactivityTimeRemaining = 0;
2161
+ this._isIdle = false;
2162
+ this._showWarning = false;
2163
+ this._timeRemaining = this.idleTimeoutMs;
2164
+ ctx.prevIsIdle = false;
2165
+ ctx.prevShowWarning = false;
2166
+ ctx.prevShowInactivityWarning = false;
2167
+ ctx.prevInactivityTimeRemaining = 0;
2168
+ ctx.prevTimeRemaining = this.idleTimeoutMs;
2169
+ if (hadWarning) {
2170
+ this.notify();
2171
+ }
2172
+ this.runScheduleNextCheck(ctx);
2173
+ }
2174
+ setupEventHandlers() {
2175
+ if (typeof window === "undefined") return;
2176
+ const ctx = {
2177
+ warningTimer: null,
2178
+ logoutTimer: null,
2179
+ countdownInterval: null,
2180
+ activityThrottleTimer: null,
2181
+ lastActivity: Date.now(),
2182
+ prevIsIdle: false,
2183
+ prevShowWarning: false,
2184
+ prevShowInactivityWarning: false,
2185
+ prevInactivityTimeRemaining: 0,
2186
+ prevTimeRemaining: this.idleTimeoutMs
2132
2187
  };
2133
2188
  const activityEvents = ["mousedown", "mousemove", "keypress", "scroll", "touchstart", "click"];
2134
- let activityThrottleTimer = null;
2135
2189
  const handleActivity = () => {
2136
- if (activityThrottleTimer) {
2137
- return;
2138
- }
2139
- activityThrottleTimer = setTimeout(() => {
2140
- activityThrottleTimer = null;
2141
- resetTimers();
2190
+ if (ctx.activityThrottleTimer) return;
2191
+ ctx.activityThrottleTimer = setTimeout(() => {
2192
+ ctx.activityThrottleTimer = null;
2193
+ this.runResetTimers(ctx);
2142
2194
  }, 1e3);
2143
2195
  };
2144
2196
  activityEvents.forEach((event) => {
2145
2197
  document.addEventListener(event, handleActivity, true);
2146
2198
  });
2147
- updateState(true);
2148
- scheduleNextCheck();
2199
+ this.runUpdateState(ctx, true);
2200
+ this.runScheduleNextCheck(ctx);
2149
2201
  this.cleanupHandlers = () => {
2150
- if (warningTimer) {
2151
- clearTimeout(warningTimer);
2152
- warningTimer = null;
2202
+ if (ctx.warningTimer) {
2203
+ clearTimeout(ctx.warningTimer);
2204
+ ctx.warningTimer = null;
2153
2205
  }
2154
- if (logoutTimer) {
2155
- clearTimeout(logoutTimer);
2156
- logoutTimer = null;
2206
+ if (ctx.logoutTimer) {
2207
+ clearTimeout(ctx.logoutTimer);
2208
+ ctx.logoutTimer = null;
2157
2209
  }
2158
- if (countdownInterval) {
2159
- clearInterval(countdownInterval);
2160
- countdownInterval = null;
2210
+ if (ctx.countdownInterval) {
2211
+ clearInterval(ctx.countdownInterval);
2212
+ ctx.countdownInterval = null;
2161
2213
  }
2162
- if (activityThrottleTimer) {
2163
- clearTimeout(activityThrottleTimer);
2164
- activityThrottleTimer = null;
2214
+ if (ctx.activityThrottleTimer) {
2215
+ clearTimeout(ctx.activityThrottleTimer);
2216
+ ctx.activityThrottleTimer = null;
2165
2217
  }
2166
2218
  activityEvents.forEach((event) => {
2167
2219
  document.removeEventListener(event, handleActivity, true);
@@ -2176,7 +2228,6 @@ var InactivityService = class extends BaseService {
2176
2228
  this._isTracking = true;
2177
2229
  }
2178
2230
  };
2179
- var InactivityServiceContext = createContext(null);
2180
2231
  function InactivityServiceProvider({
2181
2232
  children,
2182
2233
  supabaseClient,
@@ -2391,33 +2442,7 @@ function useUnifiedAuth() {
2391
2442
  }
2392
2443
  return context;
2393
2444
  }
2394
- function UnifiedAuthContextProvider({
2395
- children,
2396
- appName,
2397
- supabaseClient: supabaseClientProp,
2398
- ..._props
2399
- }) {
2400
- const authService = useAuthService();
2401
- const organisationService = useOrganisationService();
2402
- const inactivityService = useInactivityService();
2403
- const sessionRestorationState = useSessionRestoration();
2404
- const {
2405
- hasTimedOut: sessionRestorationTimedOut,
2406
- timeoutMs: sessionRestorationTimeoutMs,
2407
- isRestoring,
2408
- restorationComplete,
2409
- restorationError
2410
- } = sessionRestorationState;
2411
- const sessionRestoration = useMemo(() => ({
2412
- isRestoring,
2413
- restorationComplete,
2414
- restorationError
2415
- }), [isRestoring, restorationComplete, restorationError]);
2416
- const eventService = useEventService();
2417
- const currentUser = authService.getUser();
2418
- const currentSession = authService.getSession();
2419
- const isAuth = !!(currentUser && currentSession);
2420
- const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
2445
+ function useAppIdResolution(supabase, appName, isAuth, currentUserId) {
2421
2446
  const [appId, setAppId] = useState(void 0);
2422
2447
  const isResolvingAppIdRef = useRef(false);
2423
2448
  const resolvedAppIdRef = useRef(void 0);
@@ -2429,54 +2454,51 @@ function UnifiedAuthContextProvider({
2429
2454
  setAppId(void 0);
2430
2455
  return;
2431
2456
  }
2432
- if (currentUser?.id && resolvedUserIdRef.current && resolvedUserIdRef.current !== currentUser.id) {
2457
+ if (currentUserId && resolvedUserIdRef.current && resolvedUserIdRef.current !== currentUserId) {
2433
2458
  resolvedAppIdRef.current = void 0;
2434
2459
  resolvedUserIdRef.current = void 0;
2435
2460
  setAppId(void 0);
2436
2461
  }
2437
- const currentUserId = currentUser?.id;
2438
- if (isAuth && currentUserId && supabase && appName && resolvedUserIdRef.current !== currentUserId && // Haven't resolved for this user yet
2439
- !isResolvingAppIdRef.current) {
2440
- isResolvingAppIdRef.current = true;
2441
- resolvedUserIdRef.current = currentUserId;
2442
- const userId = currentUserId;
2443
- const appNameValue = appName;
2444
- import('./api-F47QJ7FX.js').then(async ({ resolveAppContext, setupRBAC: setupRBAC2 }) => {
2445
- try {
2446
- setupRBAC2(supabase);
2447
- const result = await resolveAppContext({
2448
- userId,
2449
- appName: appNameValue
2450
- });
2451
- if (result?.appId) {
2452
- resolvedAppIdRef.current = result.appId;
2453
- setAppId(result.appId);
2454
- } else {
2455
- resolvedUserIdRef.current = void 0;
2456
- }
2457
- } catch (error) {
2458
- logger.error("UnifiedAuthProvider", "Failed to resolve appId on login", {
2459
- error: error instanceof Error ? error.message : String(error),
2460
- appName: appNameValue,
2461
- userId
2462
- });
2462
+ const shouldResolve = isAuth && currentUserId && supabase && appName && resolvedUserIdRef.current !== currentUserId && !isResolvingAppIdRef.current;
2463
+ if (!shouldResolve) return;
2464
+ isResolvingAppIdRef.current = true;
2465
+ resolvedUserIdRef.current = currentUserId;
2466
+ const userId = currentUserId;
2467
+ const appNameValue = appName;
2468
+ import('./api-BZR2CYXL.js').then(async ({ resolveAppContext, setupRBAC: setupRBAC2 }) => {
2469
+ try {
2470
+ setupRBAC2(supabase);
2471
+ const result = await resolveAppContext({ userId, appName: appNameValue });
2472
+ if (result.ok && result.data?.appId) {
2473
+ const appIdValue = result.data.appId;
2474
+ resolvedAppIdRef.current = appIdValue;
2475
+ setAppId(appIdValue);
2476
+ } else {
2463
2477
  resolvedUserIdRef.current = void 0;
2464
- } finally {
2465
- isResolvingAppIdRef.current = false;
2466
2478
  }
2467
- }).catch((importError) => {
2468
- logger.error("UnifiedAuthProvider", "Failed to import RBAC API", importError);
2469
- isResolvingAppIdRef.current = false;
2479
+ } catch (error) {
2480
+ logger.error("UnifiedAuthProvider", "Failed to resolve appId on login", {
2481
+ error: error instanceof Error ? error.message : String(error),
2482
+ appName: appNameValue,
2483
+ userId
2484
+ });
2470
2485
  resolvedUserIdRef.current = void 0;
2471
- });
2472
- }
2473
- }, [isAuth, currentUser?.id, supabase, appName]);
2486
+ } finally {
2487
+ isResolvingAppIdRef.current = false;
2488
+ }
2489
+ }).catch((importError) => {
2490
+ logger.error("UnifiedAuthProvider", "Failed to import RBAC API", importError);
2491
+ isResolvingAppIdRef.current = false;
2492
+ resolvedUserIdRef.current = void 0;
2493
+ });
2494
+ }, [isAuth, currentUserId, supabase, appName]);
2495
+ return appId;
2496
+ }
2497
+ function useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService) {
2474
2498
  const [, forceUpdate] = useReducer((x) => x + 1, 0);
2475
2499
  const forceUpdateTimeoutRef = useRef(null);
2476
2500
  const debouncedForceUpdate = useCallback(() => {
2477
- if (forceUpdateTimeoutRef.current) {
2478
- clearTimeout(forceUpdateTimeoutRef.current);
2479
- }
2501
+ if (forceUpdateTimeoutRef.current) clearTimeout(forceUpdateTimeoutRef.current);
2480
2502
  forceUpdateTimeoutRef.current = setTimeout(() => {
2481
2503
  forceUpdate();
2482
2504
  forceUpdateTimeoutRef.current = null;
@@ -2493,20 +2515,86 @@ function UnifiedAuthContextProvider({
2493
2515
  inactivityServiceRef.current = inactivityService;
2494
2516
  }, [authService, organisationService, eventService, inactivityService]);
2495
2517
  useEffect(() => {
2496
- const unsubscribeAuth = authServiceRef.current.subscribe(debouncedForceUpdate);
2497
- const unsubscribeOrg = organisationServiceRef.current.subscribe(debouncedForceUpdate);
2498
- const unsubscribeEvent = eventServiceRef.current.subscribe(debouncedForceUpdate);
2499
- const unsubscribeInactivity = inactivityServiceRef.current.subscribe(debouncedForceUpdate);
2518
+ const unsubAuth = authServiceRef.current.subscribe(debouncedForceUpdate);
2519
+ const unsubOrg = organisationServiceRef.current.subscribe(debouncedForceUpdate);
2520
+ const unsubEvent = eventServiceRef.current.subscribe(debouncedForceUpdate);
2521
+ const unsubInactivity = inactivityServiceRef.current.subscribe(debouncedForceUpdate);
2500
2522
  return () => {
2501
- unsubscribeAuth();
2502
- unsubscribeOrg();
2503
- unsubscribeEvent();
2504
- unsubscribeInactivity();
2505
- if (forceUpdateTimeoutRef.current) {
2506
- clearTimeout(forceUpdateTimeoutRef.current);
2507
- }
2523
+ unsubAuth();
2524
+ unsubOrg();
2525
+ unsubEvent();
2526
+ unsubInactivity();
2527
+ if (forceUpdateTimeoutRef.current) clearTimeout(forceUpdateTimeoutRef.current);
2508
2528
  };
2509
2529
  }, [debouncedForceUpdate]);
2530
+ }
2531
+ function useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase) {
2532
+ return useMemo(
2533
+ () => {
2534
+ const selectedOrganisationId = state.selectedOrganisation?.id ?? state.selectedEvent?.organisation_id ?? null;
2535
+ return {
2536
+ user: state.currentUser,
2537
+ session: state.currentSession,
2538
+ isAuthenticated: state.isAuth,
2539
+ authLoading: state.authLoading,
2540
+ authError: state.authError,
2541
+ supabase,
2542
+ signIn: callbacks.signIn,
2543
+ signUp: callbacks.signUp,
2544
+ signOut: callbacks.signOut,
2545
+ resetPassword: callbacks.resetPassword,
2546
+ updatePassword: callbacks.updatePassword,
2547
+ refreshSession: callbacks.refreshSession,
2548
+ selectedOrganisation: state.selectedOrganisation,
2549
+ selectedOrganisationId,
2550
+ organisations: state.organisations,
2551
+ userMemberships: state.userMemberships,
2552
+ organisationLoading: state.orgLoading,
2553
+ organisationError: state.organisationError,
2554
+ hasValidOrganisationContext: state.hasValidOrganisationContext,
2555
+ isContextReady: state.isContextReady,
2556
+ switchOrganisation: callbacks.switchOrganisation,
2557
+ getUserRole: callbacks.getUserRole,
2558
+ validateOrganisationAccess: callbacks.validateOrganisationAccess,
2559
+ refreshOrganisations: callbacks.refreshOrganisations,
2560
+ ensureOrganisationContext: callbacks.ensureOrganisationContext,
2561
+ isOrganisationSecure: callbacks.isOrganisationSecure,
2562
+ getPrimaryOrganisation: callbacks.getPrimaryOrganisation,
2563
+ events: state.events,
2564
+ selectedEvent: state.selectedEvent,
2565
+ selectedEventId: state.selectedEvent?.event_id ?? null,
2566
+ eventLoading: state.eventLoading,
2567
+ eventError: state.eventError,
2568
+ setSelectedEvent: callbacks.setSelectedEvent,
2569
+ refreshEvents: callbacks.refreshEvents,
2570
+ showInactivityWarning: state.inactivityState.showInactivityWarning,
2571
+ inactivityTimeRemaining: state.inactivityState.inactivityTimeRemaining,
2572
+ isIdle: state.inactivityState.isIdle,
2573
+ timeRemaining: state.inactivityState.timeRemaining,
2574
+ showWarning: state.inactivityState.showWarning,
2575
+ isTracking: state.inactivityState.isTracking,
2576
+ resetActivity: callbacks.resetActivity,
2577
+ startTracking: callbacks.startTracking,
2578
+ stopTracking: callbacks.stopTracking,
2579
+ handleIdleLogout: callbacks.handleIdleLogout,
2580
+ handleStaySignedIn: callbacks.handleStaySignedIn,
2581
+ handleSignOutNow: callbacks.handleSignOutNow,
2582
+ appName,
2583
+ appId,
2584
+ isLoading: state.totalLoading,
2585
+ hasErrors: state.hasErrors,
2586
+ sessionRestoration: state.sessionRestoration,
2587
+ sessionRestorationTimedOut: state.sessionRestorationTimedOut,
2588
+ sessionRestorationTimeoutMs: state.sessionRestorationTimeoutMs
2589
+ };
2590
+ },
2591
+ [state, callbacks, appId, appName, supabase]
2592
+ );
2593
+ }
2594
+ function useUnifiedAuthStateAndCallbacks(authService, organisationService, eventService, inactivityService, sessionRestoration, sessionRestorationTimedOut, sessionRestorationTimeoutMs, appName, userOverride, sessionOverride) {
2595
+ const currentUser = userOverride !== void 0 ? userOverride : authService.getUser();
2596
+ const currentSession = sessionOverride !== void 0 ? sessionOverride : authService.getSession();
2597
+ const isAuth = !!(currentUser && currentSession);
2510
2598
  const authLoading = authService.isLoading();
2511
2599
  const orgLoading = organisationService.isLoading();
2512
2600
  const eventLoading = eventService.isLoading();
@@ -2514,23 +2602,16 @@ function UnifiedAuthContextProvider({
2514
2602
  const shouldIncludeOrgLoading = appName !== "ADMIN" && appName !== "PORTAL";
2515
2603
  const totalLoading = restorationLoading || authLoading || (shouldIncludeOrgLoading ? orgLoading : false) || eventLoading;
2516
2604
  const authError = authService.getError();
2517
- const rawSelectedOrganisation = organisationService.getSelectedOrganisation();
2605
+ const selectedOrganisation = organisationService.getSelectedOrganisation();
2518
2606
  const organisationError = organisationService.getError();
2519
- const selectedOrganisation = rawSelectedOrganisation;
2520
2607
  const hasValidOrganisationContext = organisationService.hasValidOrganisationContext();
2521
2608
  const isContextReady = organisationService.isContextReady();
2522
2609
  const rawEvents = eventService.getEvents();
2523
2610
  const rawOrganisations = organisationService.getOrganisations();
2524
2611
  const rawUserMemberships = organisationService.getUserMemberships();
2525
- const events = useMemo(() => {
2526
- return rawEvents;
2527
- }, [rawEvents]);
2528
- const organisations = useMemo(() => {
2529
- return rawOrganisations;
2530
- }, [rawOrganisations]);
2531
- const userMemberships = useMemo(() => {
2532
- return rawUserMemberships;
2533
- }, [rawUserMemberships]);
2612
+ const events = useMemo(() => rawEvents, [rawEvents]);
2613
+ const organisations = useMemo(() => rawOrganisations, [rawOrganisations]);
2614
+ const userMemberships = useMemo(() => rawUserMemberships, [rawUserMemberships]);
2534
2615
  const selectedEvent = eventService.getSelectedEvent();
2535
2616
  const eventError = eventService.getError();
2536
2617
  const showInactivityWarning = inactivityService.getShowInactivityWarning();
@@ -2546,14 +2627,7 @@ function UnifiedAuthContextProvider({
2546
2627
  timeRemaining,
2547
2628
  showWarning,
2548
2629
  isTracking
2549
- }), [
2550
- showInactivityWarning,
2551
- inactivityTimeRemaining,
2552
- isIdle,
2553
- timeRemaining,
2554
- showWarning,
2555
- isTracking
2556
- ]);
2630
+ }), [showInactivityWarning, inactivityTimeRemaining, isIdle, timeRemaining, showWarning, isTracking]);
2557
2631
  const hasErrors = !!(authError || organisationError || eventError || sessionRestoration.restorationError);
2558
2632
  const signIn = useCallback((email, password) => authService.signIn(email, password), [authService]);
2559
2633
  const signUp = useCallback((email, password) => authService.signUp(email, password), [authService]);
@@ -2576,94 +2650,12 @@ function UnifiedAuthContextProvider({
2576
2650
  const handleIdleLogout = useCallback(() => inactivityService.handleIdleLogout(), [inactivityService]);
2577
2651
  const handleStaySignedIn = useCallback(() => inactivityService.handleStaySignedIn(), [inactivityService]);
2578
2652
  const handleSignOutNow = useCallback(() => inactivityService.handleSignOutNow(), [inactivityService]);
2579
- const prevStateRef = useRef(null);
2580
- const isDev = import.meta.env.DEV || import.meta.env.MODE === "development";
2581
- if (isDev) {
2582
- const currentState = {
2583
- isAuthenticated: isAuth,
2584
- userEmail: currentUser?.email,
2585
- totalLoading
2586
- };
2587
- const prevState = prevStateRef.current;
2588
- if (!prevState || prevState.isAuthenticated !== currentState.isAuthenticated || prevState.userEmail !== currentState.userEmail || prevState.totalLoading !== currentState.totalLoading) {
2589
- prevStateRef.current = currentState;
2590
- }
2591
- }
2592
- const contextValue = useMemo(() => {
2593
- return {
2594
- // Auth state
2595
- user: currentUser,
2596
- session: currentSession,
2597
- isAuthenticated: isAuth,
2598
- authLoading,
2599
- authError,
2600
- supabase,
2601
- // Auth methods
2602
- signIn,
2603
- signUp,
2604
- signOut,
2605
- resetPassword,
2606
- updatePassword,
2607
- refreshSession,
2608
- // Organisation state
2609
- selectedOrganisation,
2610
- selectedOrganisationId: selectedOrganisation?.id || null,
2611
- organisations,
2612
- userMemberships,
2613
- organisationLoading: orgLoading,
2614
- organisationError,
2615
- hasValidOrganisationContext,
2616
- isContextReady,
2617
- // Organisation methods
2618
- switchOrganisation,
2619
- getUserRole,
2620
- validateOrganisationAccess,
2621
- refreshOrganisations,
2622
- ensureOrganisationContext,
2623
- isOrganisationSecure,
2624
- getPrimaryOrganisation,
2625
- // Event state
2626
- events,
2627
- selectedEvent,
2628
- selectedEventId: selectedEvent?.event_id || null,
2629
- eventLoading,
2630
- eventError,
2631
- // Event methods
2632
- setSelectedEvent,
2633
- refreshEvents,
2634
- // Inactivity state
2635
- showInactivityWarning: inactivityState.showInactivityWarning,
2636
- inactivityTimeRemaining: inactivityState.inactivityTimeRemaining,
2637
- isIdle: inactivityState.isIdle,
2638
- timeRemaining: inactivityState.timeRemaining,
2639
- showWarning: inactivityState.showWarning,
2640
- isTracking: inactivityState.isTracking,
2641
- // Inactivity methods
2642
- resetActivity,
2643
- startTracking,
2644
- stopTracking,
2645
- handleIdleLogout,
2646
- handleStaySignedIn,
2647
- handleSignOutNow,
2648
- // Additional unified properties
2649
- appName,
2650
- appId,
2651
- // Resolved immediately on login
2652
- isLoading: totalLoading,
2653
- hasErrors,
2654
- sessionRestoration,
2655
- sessionRestorationTimedOut,
2656
- sessionRestorationTimeoutMs
2657
- };
2658
- }, [
2659
- // All primitive values extracted from services
2660
- // Note: Arrays/objects from services are stable references (same reference unless data changes)
2653
+ const state = useMemo(() => ({
2661
2654
  currentUser,
2662
2655
  currentSession,
2663
2656
  isAuth,
2664
2657
  authLoading,
2665
2658
  authError,
2666
- supabase,
2667
2659
  selectedOrganisation,
2668
2660
  organisations,
2669
2661
  userMemberships,
@@ -2676,15 +2668,58 @@ function UnifiedAuthContextProvider({
2676
2668
  eventLoading,
2677
2669
  eventError,
2678
2670
  inactivityState,
2679
- // Use memoized object instead of individual values
2680
2671
  totalLoading,
2681
2672
  hasErrors,
2682
- appName,
2683
- appId,
2684
2673
  sessionRestoration,
2685
2674
  sessionRestorationTimedOut,
2686
- sessionRestorationTimeoutMs,
2687
- // Stable function references from useCallback (services are stable, so callbacks are too)
2675
+ sessionRestorationTimeoutMs
2676
+ }), [
2677
+ currentUser,
2678
+ currentSession,
2679
+ isAuth,
2680
+ authLoading,
2681
+ authError,
2682
+ selectedOrganisation,
2683
+ organisations,
2684
+ userMemberships,
2685
+ orgLoading,
2686
+ organisationError,
2687
+ hasValidOrganisationContext,
2688
+ isContextReady,
2689
+ events,
2690
+ selectedEvent,
2691
+ eventLoading,
2692
+ eventError,
2693
+ inactivityState,
2694
+ totalLoading,
2695
+ hasErrors,
2696
+ sessionRestoration,
2697
+ sessionRestorationTimedOut,
2698
+ sessionRestorationTimeoutMs
2699
+ ]);
2700
+ const callbacks = useMemo(() => ({
2701
+ signIn,
2702
+ signUp,
2703
+ signOut,
2704
+ resetPassword,
2705
+ updatePassword,
2706
+ refreshSession,
2707
+ switchOrganisation,
2708
+ getUserRole,
2709
+ validateOrganisationAccess,
2710
+ refreshOrganisations,
2711
+ ensureOrganisationContext,
2712
+ isOrganisationSecure,
2713
+ getPrimaryOrganisation,
2714
+ setSelectedEvent,
2715
+ refreshEvents,
2716
+ resetActivity,
2717
+ startTracking,
2718
+ stopTracking,
2719
+ handleIdleLogout,
2720
+ handleStaySignedIn,
2721
+ handleSignOutNow
2722
+ }), [
2688
2723
  signIn,
2689
2724
  signUp,
2690
2725
  signOut,
@@ -2707,6 +2742,48 @@ function UnifiedAuthContextProvider({
2707
2742
  handleStaySignedIn,
2708
2743
  handleSignOutNow
2709
2744
  ]);
2745
+ return { state, callbacks };
2746
+ }
2747
+ function UnifiedAuthContextProvider({
2748
+ children,
2749
+ appName,
2750
+ supabaseClient: supabaseClientProp,
2751
+ user: userFromParent,
2752
+ session: sessionFromParent
2753
+ }) {
2754
+ const authService = useAuthService();
2755
+ const organisationService = useOrganisationService();
2756
+ const inactivityService = useInactivityService();
2757
+ const eventService = useEventService();
2758
+ const sessionRestorationState = useSessionRestoration();
2759
+ const sessionRestoration = useMemo(() => ({
2760
+ isRestoring: sessionRestorationState.isRestoring,
2761
+ restorationComplete: sessionRestorationState.restorationComplete,
2762
+ restorationError: sessionRestorationState.restorationError
2763
+ }), [sessionRestorationState.isRestoring, sessionRestorationState.restorationComplete, sessionRestorationState.restorationError]);
2764
+ const { hasTimedOut: sessionRestorationTimedOut, timeoutMs: sessionRestorationTimeoutMs } = sessionRestorationState;
2765
+ const currentUser = userFromParent !== void 0 ? userFromParent : authService.getUser();
2766
+ const currentSession = sessionFromParent !== void 0 ? sessionFromParent : authService.getSession();
2767
+ const isAuth = !!(currentUser && currentSession);
2768
+ const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
2769
+ const appId = useAppIdResolution(supabase, appName, isAuth, currentUser?.id);
2770
+ useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService);
2771
+ const { state, callbacks } = useUnifiedAuthStateAndCallbacks(
2772
+ authService,
2773
+ organisationService,
2774
+ eventService,
2775
+ inactivityService,
2776
+ sessionRestoration,
2777
+ sessionRestorationTimedOut,
2778
+ sessionRestorationTimeoutMs,
2779
+ appName,
2780
+ currentUser,
2781
+ currentSession
2782
+ );
2783
+ const contextValue = useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase);
2784
+ useEffect(() => {
2785
+ if (appName) setPrintAppName(appName);
2786
+ }, [appName]);
2710
2787
  return /* @__PURE__ */ jsx(UnifiedAuthContext.Provider, { value: contextValue, children });
2711
2788
  }
2712
2789
  function EventServiceProviderWrapper({
@@ -2754,8 +2831,10 @@ function ServiceAwareProviders({
2754
2831
  const unsubscribe = authService.subscribe(() => {
2755
2832
  const newUser = authService.getUser();
2756
2833
  const newSession = authService.getSession();
2757
- setUserState(newUser);
2758
- setSessionState(newSession);
2834
+ flushSync(() => {
2835
+ setUserState(newUser);
2836
+ setSessionState(newSession);
2837
+ });
2759
2838
  });
2760
2839
  return unsubscribe;
2761
2840
  }, [authService]);
@@ -2788,6 +2867,8 @@ function ServiceAwareProviders({
2788
2867
  {
2789
2868
  appName,
2790
2869
  supabaseClient,
2870
+ user,
2871
+ session,
2791
2872
  persistState,
2792
2873
  enablePersistence,
2793
2874
  requireOrganisationContext,
@@ -2837,8 +2918,8 @@ function UnifiedAuthProvider({
2837
2918
  try {
2838
2919
  setupRBAC(supabaseClient);
2839
2920
  logger.debug("UnifiedAuthProvider", "RBAC initialized synchronously");
2840
- } catch (err) {
2841
- logger.error("UnifiedAuthProvider", "Failed to initialize RBAC", err);
2921
+ } catch (err2) {
2922
+ logger.error("UnifiedAuthProvider", "Failed to initialize RBAC", err2);
2842
2923
  }
2843
2924
  }
2844
2925
  return /* @__PURE__ */ jsx(AuthServiceProvider, { supabaseClient, appName, children: /* @__PURE__ */ jsx(