@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,11 +1,13 @@
1
- import { AccessDenied, useEvents } from './chunk-X5EAU5G7.js';
2
- import { useResolvedScope, scopeEqual, useCan, Alert, AlertTitle, useMultiplePermissions } from './chunk-KYURMOQM.js';
3
- import { useUnifiedAuth, useOrganisations } from './chunk-Y4PF6HIM.js';
4
- import { getRBACLogger, isSuperAdmin } from './chunk-LNHFAF4X.js';
5
- import { LoadingSpinner } from './chunk-UZNAFKGW.js';
1
+ import { AccessDenied } from './chunk-PCSHBLPB.js';
2
+ import { useResolvedScope, scopeEqual, useCan, Alert, AlertTitle, useMultiplePermissions } from './chunk-V7FTM2LU.js';
3
+ import { useEvents } from './chunk-WY6Y7KC3.js';
4
+ import { useUnifiedAuth, useOrganisations } from './chunk-4R3T5ENU.js';
5
+ import { setPrintTitle } from './chunk-D6BMFMQZ.js';
6
+ import { getRBACLogger, isSuperAdmin } from './chunk-7A6IMHH2.js';
7
+ import { cn, LoadingSpinner } from './chunk-UZNAFKGW.js';
6
8
  import { createLogger } from './chunk-BTHN5MKC.js';
7
- import React, { useRef, useMemo, useState, useEffect, useCallback } from 'react';
8
- import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
9
+ import React, { useEffect, useRef, useMemo, useState, useCallback } from 'react';
10
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
11
 
10
12
  // src/rbac/types/functions.ts
11
13
  var RPCFunction = /* @__PURE__ */ ((RPCFunction2) => {
@@ -45,57 +47,37 @@ var RBACErrorCode = /* @__PURE__ */ ((RBACErrorCode2) => {
45
47
  return RBACErrorCode2;
46
48
  })(RBACErrorCode || {});
47
49
  var logger = getRBACLogger();
48
- var PagePermissionGuardComponent = ({
49
- pageName,
50
- operation,
51
- children,
52
- fallback = /* @__PURE__ */ jsx(AccessDenied, {}),
53
- strictMode = true,
54
- auditLog = true,
55
- pageId,
56
- scope,
57
- onDenied,
58
- loading = /* @__PURE__ */ jsx(DefaultLoading, {})
59
- }) => {
60
- const renderCountRef = useRef(0);
61
- renderCountRef.current += 1;
62
- useMemo(() => Math.random().toString(36).substr(2, 9), []);
63
- const { user, selectedOrganisation, selectedEvent, supabase, appId: contextAppId, appName } = useUnifiedAuth();
64
- const [hasChecked, setHasChecked] = useState(false);
65
- const hasLoggedSuperAdminRef = useRef(false);
66
- const effectivePageId = useMemo(() => {
67
- return pageId || pageName;
68
- }, [pageId, pageName]);
50
+ function useSuperAdminCheck(userId) {
69
51
  const [isSuperAdmin2, setIsSuperAdmin] = useState(null);
70
52
  useEffect(() => {
71
- if (!user?.id) {
53
+ if (!userId) {
72
54
  setIsSuperAdmin(false);
73
55
  return;
74
56
  }
75
57
  let cancelled = false;
58
+ const startTime = Date.now();
76
59
  const checkSuperAdmin = async () => {
77
- const startTime = Date.now();
78
60
  try {
79
- const { isSuperAdmin: checkSuperAdmin2 } = await import('./api-F47QJ7FX.js');
61
+ const { isSuperAdmin: checkSuperAdmin2 } = await import('./api-BZR2CYXL.js');
80
62
  const timeoutPromise = new Promise((_, reject) => {
81
63
  setTimeout(() => reject(new Error("Super admin check timeout")), 1e4);
82
64
  });
83
- const isSuper = await Promise.race([
84
- checkSuperAdmin2(user.id),
65
+ const result = await Promise.race([
66
+ checkSuperAdmin2(userId),
85
67
  timeoutPromise
86
68
  ]);
87
69
  const elapsed = Date.now() - startTime;
88
70
  if (!cancelled) {
71
+ const isSuper = result.ok && result.data;
89
72
  setIsSuperAdmin(isSuper);
90
73
  if (false) ;
91
74
  }
92
75
  } catch (err) {
93
76
  const elapsed = Date.now() - startTime;
94
77
  if (!cancelled) {
95
- const logger3 = getRBACLogger();
96
- logger3.error("[PagePermissionGuard] Error checking super admin", {
78
+ logger.error("[PagePermissionGuard] Error checking super admin", {
97
79
  error: err,
98
- userId: user.id,
80
+ userId,
99
81
  elapsedMs: elapsed
100
82
  });
101
83
  setIsSuperAdmin(false);
@@ -106,32 +88,33 @@ var PagePermissionGuardComponent = ({
106
88
  return () => {
107
89
  cancelled = true;
108
90
  };
109
- }, [user?.id]);
91
+ }, [userId]);
92
+ return { isSuperAdmin: isSuperAdmin2 };
93
+ }
94
+ function usePageGuardScope({
95
+ supabase,
96
+ selectedOrganisationId,
97
+ selectedEventId,
98
+ selectedEventOrganisationId,
99
+ scope,
100
+ contextAppId,
101
+ appName,
102
+ isSuperAdmin: isSuperAdmin2
103
+ }) {
110
104
  const { resolvedScope: hookResolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
111
105
  supabase,
112
- selectedOrganisationId: selectedOrganisation?.id || null,
113
- selectedEventId: selectedEvent?.event_id || null,
114
- selectedEventOrganisationId: selectedEvent?.organisation_id || null
106
+ selectedOrganisationId,
107
+ selectedEventId,
108
+ selectedEventOrganisationId
115
109
  });
116
- const shouldBypassScopeForSuperAdmin = isSuperAdmin2 === true;
117
110
  const allowsOptionalContexts = useMemo(() => appName === "PORTAL" || appName === "ADMIN", [appName]);
118
- const effectiveScope = useMemo(() => scope || (hookResolvedScope ? {
119
- ...hookResolvedScope,
120
- appId: hookResolvedScope.appId || (allowsOptionalContexts ? contextAppId : void 0)
121
- } : allowsOptionalContexts && contextAppId ? {
122
- organisationId: void 0,
123
- eventId: void 0,
124
- appId: contextAppId
125
- } : selectedEvent?.event_id ? {
126
- organisationId: void 0,
127
- // Will be derived from event
128
- eventId: selectedEvent.event_id,
129
- appId: contextAppId || void 0
130
- } : null), [scope, hookResolvedScope, allowsOptionalContexts, contextAppId, selectedEvent?.event_id]);
131
- const checkError = scopeError;
132
- const permission = useMemo(() => {
133
- return `${operation}:page.${pageName}`;
134
- }, [operation, pageName]);
111
+ const effectiveScope = useMemo(
112
+ () => scope || (hookResolvedScope ? {
113
+ ...hookResolvedScope,
114
+ appId: hookResolvedScope.appId || (allowsOptionalContexts ? contextAppId : void 0)
115
+ } : allowsOptionalContexts && contextAppId ? { organisationId: void 0, eventId: void 0, appId: contextAppId } : selectedEventId ? { organisationId: void 0, eventId: selectedEventId, appId: contextAppId || void 0 } : null),
116
+ [scope, hookResolvedScope, allowsOptionalContexts, contextAppId, selectedEventId]
117
+ );
135
118
  const prevScopeRef = useRef(null);
136
119
  const stableScope = useMemo(() => {
137
120
  if (allowsOptionalContexts && effectiveScope) {
@@ -140,9 +123,7 @@ var PagePermissionGuardComponent = ({
140
123
  appId: effectiveScope.appId || contextAppId || void 0,
141
124
  eventId: effectiveScope.eventId
142
125
  };
143
- if (scopeEqual(prevScopeRef.current, newScope2)) {
144
- return prevScopeRef.current;
145
- }
126
+ if (scopeEqual(prevScopeRef.current, newScope2)) return prevScopeRef.current;
146
127
  prevScopeRef.current = newScope2;
147
128
  return newScope2;
148
129
  }
@@ -153,93 +134,123 @@ var PagePermissionGuardComponent = ({
153
134
  } : {
154
135
  organisationId: effectiveScope?.organisationId || void 0,
155
136
  appId: effectiveScope?.appId || contextAppId || void 0,
156
- eventId: effectiveScope?.eventId || selectedEvent?.event_id || void 0
137
+ eventId: effectiveScope?.eventId || selectedEventId || void 0
157
138
  };
158
- if (scopeEqual(prevScopeRef.current, newScope)) {
159
- return prevScopeRef.current;
160
- }
139
+ if (scopeEqual(prevScopeRef.current, newScope)) return prevScopeRef.current;
161
140
  prevScopeRef.current = newScope;
162
141
  return newScope;
163
- }, [effectiveScope, contextAppId, selectedEvent?.event_id, allowsOptionalContexts]);
164
- const scopeForPermissionCheck = shouldBypassScopeForSuperAdmin && !stableScope?.organisationId ? {
165
- organisationId: void 0,
166
- appId: contextAppId || void 0,
167
- eventId: selectedEvent?.event_id || void 0
168
- } : stableScope;
169
- const shouldSkipPermissionCheck = isSuperAdmin2 === true;
142
+ }, [effectiveScope, contextAppId, selectedEventId, allowsOptionalContexts]);
143
+ const shouldBypassScopeForSuperAdmin = isSuperAdmin2 === true;
144
+ const scopeForPermissionCheck = shouldBypassScopeForSuperAdmin && !stableScope?.organisationId ? { organisationId: void 0, appId: contextAppId || void 0, eventId: selectedEventId || void 0 } : stableScope;
145
+ return {
146
+ effectiveScope,
147
+ stableScope,
148
+ scopeForPermissionCheck,
149
+ scopeLoading,
150
+ scopeError: scopeError ?? null,
151
+ allowsOptionalContexts
152
+ };
153
+ }
154
+
155
+ // src/rbac/hooks/usePagePermissionCheck.ts
156
+ var dummyScope = { organisationId: void 0, appId: void 0, eventId: void 0 };
157
+ function usePagePermissionCheck({
158
+ userId,
159
+ scopeForPermissionCheck,
160
+ shouldSkipPermissionCheck,
161
+ contextAppId,
162
+ permission,
163
+ effectivePageId,
164
+ isSuperAdmin: isSuperAdmin2,
165
+ appName
166
+ }) {
167
+ const scope = shouldSkipPermissionCheck ? { ...dummyScope, appId: contextAppId } : scopeForPermissionCheck ?? dummyScope;
170
168
  const { can, isLoading: canIsLoading, error: canError } = useCan(
171
- user?.id || "",
172
- shouldSkipPermissionCheck ? { organisationId: void 0, appId: contextAppId || void 0, eventId: void 0 } : scopeForPermissionCheck,
169
+ userId,
170
+ scope,
173
171
  permission,
174
172
  effectivePageId,
175
173
  true,
176
- // Use cache
177
174
  isSuperAdmin2,
178
- // precomputedSuperAdmin - null if checking, true/false if checked
179
175
  appName
180
- // Pass appName for PORTAL/ADMIN special case
181
176
  );
182
177
  const effectiveCan = shouldSkipPermissionCheck ? true : can;
183
178
  const effectiveIsLoading = shouldSkipPermissionCheck ? false : canIsLoading;
184
- const isLoading = shouldBypassScopeForSuperAdmin ? effectiveIsLoading : scopeLoading || effectiveIsLoading;
185
- const error = checkError || canError;
179
+ return { can, effectiveCan, canIsLoading: effectiveIsLoading, canError: canError ?? null };
180
+ }
181
+ var logger2 = getRBACLogger();
182
+ function usePageAccessLogging(options) {
183
+ const {
184
+ setHasChecked,
185
+ hasChecked,
186
+ isLoading,
187
+ error,
188
+ effectiveCan,
189
+ pageName,
190
+ operation,
191
+ onDenied,
192
+ auditLog: _auditLog,
193
+ userId,
194
+ effectiveScope,
195
+ isSuperAdmin: isSuperAdmin2,
196
+ strictMode,
197
+ shouldBypassScopeForSuperAdmin,
198
+ effectivePageId,
199
+ allowsOptionalContexts,
200
+ checkError,
201
+ canError,
202
+ scopeLoading,
203
+ canIsLoading,
204
+ hasValidUser,
205
+ stableScope,
206
+ appName
207
+ } = options;
186
208
  useEffect(() => {
187
209
  if (!isLoading && !error) {
188
210
  setHasChecked(true);
189
- if (!effectiveCan && onDenied) {
190
- onDenied(pageName, operation);
191
- }
211
+ if (!effectiveCan && onDenied) onDenied(pageName, operation);
192
212
  } else if (error) {
193
213
  setHasChecked(true);
194
214
  }
195
- }, [effectiveCan, isLoading, error, pageName, operation, onDenied]);
196
- useEffect(() => {
197
- if (auditLog && hasChecked && !isLoading) {
198
- const rbacLogger = getRBACLogger();
199
- rbacLogger.debug("Page access attempt:", {
200
- pageName,
201
- operation,
202
- userId: user?.id,
203
- scope: effectiveScope,
204
- allowed: effectiveCan,
205
- isSuperAdmin: isSuperAdmin2,
206
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
207
- });
208
- }
209
- }, [auditLog, hasChecked, isLoading, pageName, operation, user?.id, effectiveScope, effectiveCan, isSuperAdmin2]);
215
+ }, [effectiveCan, isLoading, error, pageName, operation, onDenied, setHasChecked]);
210
216
  useEffect(() => {
211
217
  if (strictMode && hasChecked && !isLoading && !effectiveCan && !shouldBypassScopeForSuperAdmin) {
212
- const logger3 = getRBACLogger();
213
- logger3.error(`STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
218
+ logger2.error("STRICT MODE VIOLATION: User attempted to access protected page without permission", {
214
219
  pageName,
215
220
  operation,
216
221
  permission: `${operation}:page.${pageName}`,
217
222
  pageId: effectivePageId,
218
- userId: user?.id,
223
+ userId,
219
224
  scope: effectiveScope,
220
225
  scopeValid: allowsOptionalContexts ? true : effectiveScope !== null,
221
- // PORTAL/ADMIN allow scope without org/event
222
226
  checkError,
223
227
  canError,
224
228
  isSuperAdmin: isSuperAdmin2,
225
229
  timestamp: (/* @__PURE__ */ new Date()).toISOString()
226
230
  });
227
231
  }
228
- }, [strictMode, hasChecked, isLoading, effectiveCan, shouldBypassScopeForSuperAdmin, pageName, operation, effectivePageId, user?.id, effectiveScope, allowsOptionalContexts, checkError, canError, isSuperAdmin2]);
229
- const hasValidScopeForPagePermissions = shouldBypassScopeForSuperAdmin ? true : allowsOptionalContexts ? true : effectiveScope !== null;
230
- const hasValidUser = user && user.id;
231
- const isPermissionCheckComplete = hasChecked && !isLoading;
232
- const shouldShowAccessDenied = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && !effectiveCan;
233
- const shouldShowContent = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && effectiveCan;
234
- useRef("");
235
- useEffect(() => {
236
- }, [pageName, user?.id, isSuperAdmin2, isLoading, scopeLoading, canIsLoading, hasChecked, hasValidUser, effectiveCan, stableScope, effectiveScope]);
232
+ }, [
233
+ strictMode,
234
+ hasChecked,
235
+ isLoading,
236
+ effectiveCan,
237
+ shouldBypassScopeForSuperAdmin,
238
+ pageName,
239
+ operation,
240
+ effectivePageId,
241
+ userId,
242
+ effectiveScope,
243
+ allowsOptionalContexts,
244
+ checkError,
245
+ canError,
246
+ isSuperAdmin2
247
+ ]);
237
248
  useEffect(() => {
238
249
  if (isLoading && isSuperAdmin2 === null && hasValidUser) {
239
250
  const timeout = setTimeout(() => {
240
- logger.warn("Permission check taking longer than expected", {
251
+ logger2.warn("Permission check taking longer than expected", {
241
252
  pageName,
242
- userId: user?.id,
253
+ userId,
243
254
  isSuperAdmin: isSuperAdmin2,
244
255
  scopeLoading,
245
256
  canIsLoading,
@@ -251,30 +262,166 @@ var PagePermissionGuardComponent = ({
251
262
  }, 5e3);
252
263
  return () => clearTimeout(timeout);
253
264
  }
254
- }, [isLoading, isSuperAdmin2, hasValidUser, pageName, user?.id, scopeLoading, canIsLoading, hasChecked, stableScope, effectiveScope, appName]);
265
+ }, [
266
+ isLoading,
267
+ isSuperAdmin2,
268
+ hasValidUser,
269
+ pageName,
270
+ userId,
271
+ scopeLoading,
272
+ canIsLoading,
273
+ hasChecked,
274
+ stableScope,
275
+ effectiveScope,
276
+ appName
277
+ ]);
278
+ const hasLoggedSuperAdminRef = useRef(false);
255
279
  useEffect(() => {
256
280
  if (isSuperAdmin2 === true && hasValidUser && !hasLoggedSuperAdminRef.current && false) ;
257
- if (isSuperAdmin2 !== true) {
258
- hasLoggedSuperAdminRef.current = false;
259
- }
260
- }, [isSuperAdmin2, hasValidUser, pageName, user?.id, operation]);
261
- if (isSuperAdmin2 === true && hasValidUser) {
262
- return /* @__PURE__ */ jsx(Fragment, { children });
263
- }
264
- if (isLoading || !hasValidUser || !hasChecked || isSuperAdmin2 === null) {
265
- return loading || /* @__PURE__ */ jsx("p", { children: "Checking permissions..." });
266
- }
267
- if (checkError && !can) {
268
- return fallback;
269
- }
270
- if (shouldShowAccessDenied) {
271
- return fallback;
272
- }
273
- if (shouldShowContent) {
274
- return /* @__PURE__ */ jsx(Fragment, { children });
281
+ if (isSuperAdmin2 !== true) hasLoggedSuperAdminRef.current = false;
282
+ }, [isSuperAdmin2, hasValidUser, pageName, userId, operation]);
283
+ }
284
+ function getPageGuardView(state) {
285
+ const { isSuperAdmin: isSuperAdmin2, hasValidUser, isLoading, hasChecked, scopeError, can, effectiveCan, effectiveScope, allowsOptionalContexts, shouldBypassScopeForSuperAdmin } = state;
286
+ if (isSuperAdmin2 === true && hasValidUser) return "super-admin";
287
+ if (isLoading || !hasValidUser || !hasChecked || isSuperAdmin2 === null) return "loading";
288
+ const hasValidScope = shouldBypassScopeForSuperAdmin ? true : allowsOptionalContexts ? true : effectiveScope !== null;
289
+ const checkComplete = hasChecked && !isLoading;
290
+ if (scopeError && !can) return "denied";
291
+ if (checkComplete && hasValidScope && hasValidUser && !scopeError && !effectiveCan) return "denied";
292
+ if (checkComplete && hasValidScope && hasValidUser && !scopeError && effectiveCan) return "content";
293
+ return "fallback";
294
+ }
295
+ var PagePermissionGuardComponent = ({
296
+ pageName,
297
+ operation,
298
+ children,
299
+ fallback = /* @__PURE__ */ jsx(AccessDenied, {}),
300
+ strictMode = true,
301
+ auditLog = true,
302
+ pageId,
303
+ scope,
304
+ onDenied,
305
+ loading = /* @__PURE__ */ jsx(DefaultLoading, {}),
306
+ printPageOrientation = "portrait",
307
+ printTitle
308
+ }) => {
309
+ useEffect(() => {
310
+ if (printTitle) setPrintTitle(printTitle);
311
+ return () => {
312
+ if (typeof document !== "undefined" && document.documentElement) {
313
+ document.documentElement.style.removeProperty("--print-title");
314
+ }
315
+ };
316
+ }, [printTitle]);
317
+ const renderCountRef = useRef(0);
318
+ renderCountRef.current += 1;
319
+ useMemo(() => Math.random().toString(36).substr(2, 9), []);
320
+ const { user, selectedOrganisation, selectedEvent, supabase, appId: contextAppId, appName } = useUnifiedAuth();
321
+ const { isSuperAdmin: isSuperAdmin2 } = useSuperAdminCheck(user?.id);
322
+ const effectivePageId = useMemo(() => pageId || pageName, [pageId, pageName]);
323
+ const permission = useMemo(() => `${operation}:page.${pageName}`, [operation, pageName]);
324
+ const {
325
+ effectiveScope,
326
+ stableScope,
327
+ scopeForPermissionCheck,
328
+ scopeLoading,
329
+ scopeError,
330
+ allowsOptionalContexts
331
+ } = usePageGuardScope({
332
+ supabase,
333
+ selectedOrganisationId: selectedOrganisation?.id ?? null,
334
+ selectedEventId: selectedEvent?.event_id ?? null,
335
+ selectedEventOrganisationId: selectedEvent?.organisation_id ?? null,
336
+ scope,
337
+ contextAppId,
338
+ appName,
339
+ isSuperAdmin: isSuperAdmin2
340
+ });
341
+ const shouldBypassScopeForSuperAdmin = isSuperAdmin2 === true;
342
+ const shouldSkipPermissionCheck = isSuperAdmin2 === true;
343
+ const { can, effectiveCan, canIsLoading, canError } = usePagePermissionCheck({
344
+ userId: user?.id ?? "",
345
+ scopeForPermissionCheck,
346
+ shouldSkipPermissionCheck,
347
+ contextAppId,
348
+ permission,
349
+ effectivePageId,
350
+ isSuperAdmin: isSuperAdmin2,
351
+ appName
352
+ });
353
+ const isLoading = shouldBypassScopeForSuperAdmin ? canIsLoading : scopeLoading || canIsLoading;
354
+ const error = scopeError ?? canError;
355
+ const [hasChecked, setHasChecked] = useState(false);
356
+ const hasValidUser = Boolean(user?.id);
357
+ usePageAccessLogging({
358
+ setHasChecked,
359
+ hasChecked,
360
+ isLoading,
361
+ error,
362
+ effectiveCan,
363
+ pageName,
364
+ operation,
365
+ onDenied,
366
+ auditLog,
367
+ userId: user?.id,
368
+ effectiveScope,
369
+ isSuperAdmin: isSuperAdmin2,
370
+ strictMode,
371
+ shouldBypassScopeForSuperAdmin,
372
+ effectivePageId,
373
+ allowsOptionalContexts,
374
+ checkError: scopeError,
375
+ canError,
376
+ scopeLoading,
377
+ canIsLoading,
378
+ hasValidUser,
379
+ stableScope,
380
+ appName
381
+ });
382
+ const view = getPageGuardView({
383
+ isSuperAdmin: isSuperAdmin2,
384
+ hasValidUser,
385
+ isLoading,
386
+ hasChecked,
387
+ scopeError,
388
+ can,
389
+ effectiveCan,
390
+ effectiveScope,
391
+ allowsOptionalContexts,
392
+ shouldBypassScopeForSuperAdmin
393
+ });
394
+ switch (view) {
395
+ case "super-admin":
396
+ return /* @__PURE__ */ jsx(PageGuardLayout, { printPageOrientation, children });
397
+ case "loading":
398
+ return loading || /* @__PURE__ */ jsx("p", { children: "Checking permissions..." });
399
+ case "denied":
400
+ return fallback;
401
+ case "content":
402
+ return /* @__PURE__ */ jsx(PageGuardLayout, { printPageOrientation, withPrintPadding: true, children });
403
+ default:
404
+ return fallback;
275
405
  }
276
- return fallback;
277
406
  };
407
+ function PageGuardLayout({
408
+ children,
409
+ printPageOrientation,
410
+ withPrintPadding = false
411
+ }) {
412
+ return /* @__PURE__ */ jsx(
413
+ "main",
414
+ {
415
+ className: cn(
416
+ "px-4 w-[min(var(--app-width),100%)] mx-auto py-8",
417
+ withPrintPadding && "print:p-0 print:pb-[40mm]",
418
+ printPageOrientation === "landscape" && "print-page-landscape",
419
+ printPageOrientation === "portrait" && "print-page-portrait"
420
+ ),
421
+ children
422
+ }
423
+ );
424
+ }
278
425
  function DefaultLoading() {
279
426
  return /* @__PURE__ */ jsx(Alert, { role: "status", "aria-live": "polite", children: /* @__PURE__ */ jsxs(AlertTitle, { children: [
280
427
  /* @__PURE__ */ jsx(LoadingSpinner, { size: "sm" }),
@@ -338,8 +485,8 @@ function NavigationGuard({
338
485
  }, [auditLog, hasChecked, isLoading, navigationItem, user?.id, effectiveScope, hasRequiredPermissions, requireAll]);
339
486
  useEffect(() => {
340
487
  if (strictMode && hasChecked && !isLoading && !hasRequiredPermissions) {
341
- const logger3 = getRBACLogger();
342
- logger3.error(`STRICT MODE VIOLATION: User attempted to access protected navigation item without permission`, {
488
+ const logger4 = getRBACLogger();
489
+ logger4.error(`STRICT MODE VIOLATION: User attempted to access protected navigation item without permission`, {
343
490
  navigationItem: navigationItem.id,
344
491
  permissions: navigationItem.permissions,
345
492
  userId: user?.id,
@@ -353,8 +500,8 @@ function NavigationGuard({
353
500
  return /* @__PURE__ */ jsx(Fragment, { children: loading });
354
501
  }
355
502
  if (checkError) {
356
- const logger3 = getRBACLogger();
357
- logger3.error(`Permission check failed for navigation item ${navigationItem.id}:`, checkError);
503
+ const logger4 = getRBACLogger();
504
+ logger4.error(`Permission check failed for navigation item ${navigationItem.id}:`, checkError);
358
505
  return /* @__PURE__ */ jsx(Fragment, { children: fallback });
359
506
  }
360
507
  if (!hasRequiredPermissions) {
@@ -369,46 +516,40 @@ function DefaultLoading2() {
369
516
  "Checking..."
370
517
  ] }) });
371
518
  }
372
- function useResourcePermissions(resource, options = {}) {
373
- const { enableRead = false, requireScope = true } = options;
374
- const logger3 = createLogger("ResourcePermissions");
375
- const { user, supabase } = useUnifiedAuth();
519
+ function useResourcePermissionsSuperAdmin(userId) {
520
+ const logger4 = createLogger("ResourcePermissionsSuperAdmin");
376
521
  const [isSuperAdminUser, setIsSuperAdminUser] = useState(null);
377
- const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(() => !!user?.id);
522
+ const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(() => !!userId);
378
523
  const lastCheckedUserIdRef = useRef(null);
379
524
  const isCheckingRef = useRef(false);
380
525
  useEffect(() => {
381
- if (lastCheckedUserIdRef.current === user?.id && isSuperAdminUser !== null) {
382
- return;
383
- }
384
- if (isCheckingRef.current) {
385
- return;
386
- }
526
+ if (lastCheckedUserIdRef.current === userId && isSuperAdminUser !== null) return;
527
+ if (isCheckingRef.current) return;
387
528
  const checkSuperAdminStatus = async () => {
388
- if (!user?.id) {
529
+ if (!userId) {
389
530
  setIsSuperAdminUser(false);
390
531
  setIsCheckingSuperAdmin(false);
391
532
  lastCheckedUserIdRef.current = null;
392
533
  return;
393
534
  }
394
535
  isCheckingRef.current = true;
395
- lastCheckedUserIdRef.current = user.id;
536
+ lastCheckedUserIdRef.current = userId;
396
537
  const startTime = Date.now();
397
538
  setIsCheckingSuperAdmin(true);
398
539
  const timeoutId = setTimeout(() => {
399
- logger3.warn("useResourcePermissions", "Super admin check taking longer than 5 seconds", {
400
- userId: user?.id,
540
+ logger4.warn("useResourcePermissions", "Super admin check taking longer than 5 seconds", {
541
+ userId,
401
542
  elapsedMs: Date.now() - startTime
402
543
  });
403
544
  }, 5e3);
404
545
  try {
405
- const superAdminStatus = await isSuperAdmin(user.id);
406
- setIsSuperAdminUser(superAdminStatus);
407
- } catch (error2) {
546
+ const result = await isSuperAdmin(userId);
547
+ setIsSuperAdminUser(result.ok && result.data);
548
+ } catch (error) {
408
549
  const elapsed = Date.now() - startTime;
409
- logger3.error("useResourcePermissions", "Error checking super admin status", {
410
- userId: user?.id,
411
- error: error2,
550
+ logger4.error("useResourcePermissions", "Error checking super admin status", {
551
+ userId,
552
+ error,
412
553
  elapsedMs: elapsed
413
554
  });
414
555
  setIsSuperAdminUser(false);
@@ -419,7 +560,34 @@ function useResourcePermissions(resource, options = {}) {
419
560
  }
420
561
  };
421
562
  checkSuperAdminStatus();
422
- }, [user?.id, logger3, isSuperAdminUser]);
563
+ }, [userId, logger4, isSuperAdminUser]);
564
+ return { isSuperAdminUser, isCheckingSuperAdmin };
565
+ }
566
+
567
+ // src/rbac/hooks/useResourcePermissions.ts
568
+ function buildResourcePermissions(params) {
569
+ const createSuperAdminAwarePermission = (result) => {
570
+ if (params.isSuperAdminUser === true) return true;
571
+ return result;
572
+ };
573
+ return {
574
+ canCreate: (res) => res !== params.resource ? false : createSuperAdminAwarePermission(params.canCreateResult),
575
+ canUpdate: (res) => res !== params.resource ? false : createSuperAdminAwarePermission(params.canUpdateResult),
576
+ canDelete: (res) => res !== params.resource ? false : createSuperAdminAwarePermission(params.canDeleteResult),
577
+ canRead: (res) => {
578
+ if (!params.enableRead) return true;
579
+ if (res !== params.resource) return false;
580
+ return createSuperAdminAwarePermission(params.canReadResult);
581
+ },
582
+ scope: params.scope,
583
+ isLoading: params.isCheckingSuperAdmin || params.isLoading,
584
+ error: params.error
585
+ };
586
+ }
587
+ function useResourcePermissions(resource, options = {}) {
588
+ const { enableRead = false, requireScope = true } = options;
589
+ const { user, supabase } = useUnifiedAuth();
590
+ const { isSuperAdminUser, isCheckingSuperAdmin } = useResourcePermissionsSuperAdmin(user?.id);
423
591
  const { selectedOrganisation } = useOrganisations();
424
592
  let selectedEvent = null;
425
593
  try {
@@ -512,60 +680,239 @@ function useResourcePermissions(resource, options = {}) {
512
680
  if (enableRead && readError) return readError;
513
681
  return null;
514
682
  }, [scopeError, createError, updateError, deleteError, readError, enableRead]);
515
- return useMemo(() => {
516
- const createSuperAdminAwarePermission = (result) => {
517
- if (isSuperAdminUser === true) {
518
- return true;
519
- }
520
- return result;
521
- };
522
- return {
523
- canCreate: (res) => {
524
- if (res !== resource) {
525
- return false;
526
- }
527
- return createSuperAdminAwarePermission(canCreateResult);
528
- },
529
- canUpdate: (res) => {
530
- if (res !== resource) {
531
- return false;
532
- }
533
- return createSuperAdminAwarePermission(canUpdateResult);
534
- },
535
- canDelete: (res) => {
536
- if (res !== resource) {
537
- return false;
538
- }
539
- return createSuperAdminAwarePermission(canDeleteResult);
540
- },
541
- canRead: (res) => {
542
- if (!enableRead) {
543
- return true;
544
- }
545
- if (res !== resource) {
546
- return false;
547
- }
548
- return createSuperAdminAwarePermission(canReadResult);
549
- },
683
+ return useMemo(
684
+ () => buildResourcePermissions({
685
+ resource,
686
+ enableRead,
687
+ isSuperAdminUser,
688
+ isCheckingSuperAdmin,
689
+ canCreateResult,
690
+ canUpdateResult,
691
+ canDeleteResult,
692
+ canReadResult,
550
693
  scope,
551
- isLoading: isCheckingSuperAdmin || isLoading,
694
+ isLoading,
552
695
  error
696
+ }),
697
+ [
698
+ resource,
699
+ enableRead,
700
+ isSuperAdminUser,
701
+ isCheckingSuperAdmin,
702
+ canCreateResult,
703
+ canUpdateResult,
704
+ canDeleteResult,
705
+ canReadResult,
706
+ scope,
707
+ isLoading,
708
+ error
709
+ ]
710
+ );
711
+ }
712
+
713
+ // src/rbac/utils/roleManagementRpc.ts
714
+ var logger3 = createLogger("roleManagementRpc");
715
+ function logIfDev(message, data) {
716
+ if (import.meta.env.MODE === "development") {
717
+ if (data !== void 0) {
718
+ logger3.debug(message, data);
719
+ } else {
720
+ logger3.debug(message);
721
+ }
722
+ }
723
+ }
724
+ function formatRpcError(rpcError) {
725
+ const parts = [
726
+ rpcError.message,
727
+ rpcError.details,
728
+ rpcError.hint,
729
+ rpcError.code ? `Error code: ${rpcError.code}` : null
730
+ ].filter(Boolean);
731
+ return parts.length > 0 ? parts.join(" | ") : "Unknown RPC error";
732
+ }
733
+ function parseRevokeResponse(data) {
734
+ if (!data || !Array.isArray(data) || data.length === 0) {
735
+ logIfDev("Empty or null revoke response", { data });
736
+ return { success: false, error: "No response from database - role revocation may have failed" };
737
+ }
738
+ const result = data[0];
739
+ logIfDev("Revoke RPC result", result);
740
+ if (!result || result.success !== true) {
741
+ const errorMessage = result?.message || result?.error_code || "Role revocation failed";
742
+ return {
743
+ success: false,
744
+ message: result?.message,
745
+ error: errorMessage
553
746
  };
554
- }, [
555
- resource,
556
- isSuperAdminUser,
557
- isCheckingSuperAdmin,
558
- canCreateResult,
559
- canUpdateResult,
560
- canDeleteResult,
561
- canReadResult,
562
- enableRead,
563
- scope,
564
- isLoading,
565
- error
566
- ]);
747
+ }
748
+ return {
749
+ success: true,
750
+ message: result.message ?? "Role revoked successfully",
751
+ error: void 0
752
+ };
753
+ }
754
+ async function revokeEventAppRoleRpc(supabase, params, revokedBy) {
755
+ const contextId = `${params.event_id}:${params.app_id}`;
756
+ const rpcParams = {
757
+ p_user_id: params.user_id,
758
+ p_role_type: "event_app",
759
+ p_role_name: params.role,
760
+ p_context_id: contextId,
761
+ p_revoked_by: params.revoked_by ?? revokedBy ?? void 0
762
+ };
763
+ logIfDev("revokeEventAppRole called with", rpcParams);
764
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", rpcParams);
765
+ if (rpcError) {
766
+ logIfDev("RPC error", { message: rpcError.message, code: rpcError.code });
767
+ throw new Error(rpcError.message || "Failed to revoke role - unknown RPC error");
768
+ }
769
+ logIfDev("RPC response", { dataType: Array.isArray(data) ? "array" : typeof data });
770
+ return parseRevokeResponse(data);
771
+ }
772
+ async function grantEventAppRoleRpc(supabase, params, grantedBy) {
773
+ const contextId = `${params.event_id}:${params.app_id}`;
774
+ const rpcParams = {
775
+ p_user_id: params.user_id,
776
+ p_role_type: "event_app",
777
+ p_role_name: params.role,
778
+ p_context_id: contextId,
779
+ p_granted_by: params.granted_by ?? grantedBy ?? void 0
780
+ };
781
+ logIfDev("grantEventAppRole called with", rpcParams);
782
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", rpcParams);
783
+ if (rpcError) {
784
+ throw new Error(rpcError.message || "Failed to grant role");
785
+ }
786
+ if (!data || !Array.isArray(data) || data.length === 0) {
787
+ return { success: false, error: "No response from database - role grant may have failed" };
788
+ }
789
+ const result = data[0];
790
+ if (!result || result.success !== true) {
791
+ const errorMessage = result?.message ?? result?.error_code ?? "Role grant failed";
792
+ return {
793
+ success: false,
794
+ message: result?.message,
795
+ error: errorMessage
796
+ };
797
+ }
798
+ return {
799
+ success: true,
800
+ message: result.message ?? "Role granted successfully",
801
+ roleId: result.role_id
802
+ };
803
+ }
804
+ async function revokeRoleByIdRpc(supabase, roleId, revokedBy) {
805
+ const { data: roleData, error: fetchError } = await supabase.from("rbac_event_app_roles").select("user_id, role, event_id, app_id").eq("id", roleId).single();
806
+ if (fetchError || !roleData) {
807
+ throw new Error(fetchError?.message || "Role not found");
808
+ }
809
+ const contextId = `${roleData.event_id}:${roleData.app_id}`;
810
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
811
+ p_user_id: roleData.user_id,
812
+ p_role_type: "event_app",
813
+ p_role_name: roleData.role,
814
+ p_context_id: contextId,
815
+ p_revoked_by: revokedBy ?? void 0
816
+ });
817
+ if (rpcError) {
818
+ throw new Error(rpcError.message || "Failed to revoke role - unknown RPC error");
819
+ }
820
+ const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
821
+ if (!result) {
822
+ return { success: false, error: void 0 };
823
+ }
824
+ if (result.success === false) {
825
+ const errorMessage = result.message || result.error_code || "Role revocation failed";
826
+ return { success: false, message: result.message, error: errorMessage };
827
+ }
828
+ return {
829
+ success: true,
830
+ message: result.message ?? "Role revoked successfully",
831
+ error: void 0
832
+ };
833
+ }
834
+ function parseGrantResponse(data, fallbackError) {
835
+ const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
836
+ if (!result || !result.success) {
837
+ return {
838
+ success: false,
839
+ error: result?.message || result?.error_code || fallbackError,
840
+ message: result?.message
841
+ };
842
+ }
843
+ return {
844
+ success: true,
845
+ message: result.message ?? "Role granted successfully",
846
+ roleId: result.role_id
847
+ };
848
+ }
849
+ async function grantGlobalRoleRpc(supabase, params, grantedBy) {
850
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", {
851
+ p_user_id: params.user_id,
852
+ p_role_type: "global",
853
+ p_role_name: params.role,
854
+ p_context_id: null,
855
+ p_granted_by: params.granted_by ?? grantedBy ?? void 0
856
+ });
857
+ if (rpcError) {
858
+ throw new Error(rpcError.message || "Failed to grant role");
859
+ }
860
+ return parseGrantResponse(data, "Failed to grant role");
861
+ }
862
+ async function revokeGlobalRoleRpc(supabase, params, revokedBy) {
863
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
864
+ p_user_id: params.user_id,
865
+ p_role_type: "global",
866
+ p_role_name: params.role,
867
+ p_context_id: null,
868
+ p_revoked_by: params.revoked_by ?? revokedBy ?? void 0
869
+ });
870
+ if (rpcError) {
871
+ throw new Error(formatRpcError(rpcError));
872
+ }
873
+ const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
874
+ return {
875
+ success: result?.success === true,
876
+ message: result?.message,
877
+ error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
878
+ };
879
+ }
880
+ async function grantOrganisationRoleRpc(supabase, params, grantedBy) {
881
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", {
882
+ p_user_id: params.user_id,
883
+ p_role_type: "organisation",
884
+ p_role_name: params.role,
885
+ p_context_id: params.organisation_id,
886
+ p_granted_by: params.granted_by ?? grantedBy ?? void 0
887
+ });
888
+ if (rpcError) {
889
+ throw new Error(rpcError.message || "Failed to grant role");
890
+ }
891
+ return parseGrantResponse(data, "Failed to grant role");
892
+ }
893
+ async function revokeOrganisationRoleRpc(supabase, params, revokedBy) {
894
+ const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
895
+ p_user_id: params.user_id,
896
+ p_role_type: "organisation",
897
+ p_role_name: params.role,
898
+ p_context_id: params.organisation_id,
899
+ p_revoked_by: params.revoked_by ?? revokedBy ?? void 0
900
+ });
901
+ if (rpcError) {
902
+ throw new Error(formatRpcError(rpcError));
903
+ }
904
+ const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
905
+ return {
906
+ success: result?.success === true,
907
+ message: result?.message,
908
+ error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
909
+ };
910
+ }
911
+
912
+ // src/rbac/hooks/useRoleManagement.ts
913
+ function failureResult(errorMessage) {
914
+ return { success: false, error: errorMessage };
567
915
  }
568
- var logger2 = createLogger("useRoleManagement");
569
916
  function useRoleManagement() {
570
917
  const { user, supabase } = useUnifiedAuth();
571
918
  const [isLoading, setIsLoading] = useState(false);
@@ -573,362 +920,120 @@ function useRoleManagement() {
573
920
  if (!supabase) {
574
921
  throw new Error("useRoleManagement requires a Supabase client. Ensure UnifiedAuthProvider is configured.");
575
922
  }
576
- const revokeEventAppRole = useCallback(async (params) => {
577
- setIsLoading(true);
578
- setError(null);
579
- try {
580
- const contextId = `${params.event_id}:${params.app_id}`;
581
- const rpcParams = {
582
- p_user_id: params.user_id,
583
- p_role_type: "event_app",
584
- p_role_name: params.role,
585
- p_context_id: contextId,
586
- p_revoked_by: params.revoked_by || user?.id || void 0
587
- };
588
- if (import.meta.env.MODE === "development") {
589
- logger2.debug("revokeEventAppRole called with:", rpcParams);
590
- }
591
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", rpcParams);
592
- if (rpcError) {
593
- if (import.meta.env.MODE === "development") {
594
- logger2.error("RPC error:", {
595
- message: rpcError.message,
596
- details: rpcError.details,
597
- hint: rpcError.hint,
598
- code: rpcError.code,
599
- fullError: rpcError
600
- });
601
- }
602
- const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
603
- throw new Error(errorMessage);
604
- }
605
- if (import.meta.env.MODE === "development") {
606
- logger2.debug("RPC response:", {
607
- data,
608
- error: rpcError,
609
- dataType: Array.isArray(data) ? "array" : typeof data,
610
- dataLength: Array.isArray(data) ? data.length : "N/A"
611
- });
612
- }
613
- if (!data || !Array.isArray(data) || data.length === 0) {
614
- const errorMsg = "No response from database - role revocation may have failed";
615
- if (import.meta.env.MODE === "development") {
616
- logger2.error("Empty or null data response:", {
617
- data,
618
- dataType: typeof data,
619
- isArray: Array.isArray(data),
620
- length: Array.isArray(data) ? data.length : "N/A"
621
- });
622
- }
623
- throw new Error(errorMsg);
624
- }
625
- const result = data[0];
626
- if (import.meta.env.MODE === "development") {
627
- logger2.debug("RPC result:", {
628
- success: result?.success,
629
- message: result?.message,
630
- error_code: result?.error_code,
631
- revoked_count: result?.revoked_count,
632
- fullResult: result
633
- });
634
- }
635
- if (!result || result.success !== true) {
636
- const errorMessage = result?.message || result?.error_code || "Role revocation failed";
637
- if (import.meta.env.MODE === "development") {
638
- logger2.error("Role revocation failed:", {
639
- result,
640
- errorMessage,
641
- fullData: data,
642
- rpcParams
643
- });
644
- }
645
- return {
646
- success: false,
647
- message: result?.message || void 0,
648
- error: errorMessage
649
- };
650
- }
651
- return {
652
- success: true,
653
- message: result.message || "Role revoked successfully",
654
- error: void 0
655
- };
656
- } catch (err) {
657
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
658
- if (import.meta.env.MODE === "development") {
659
- logger2.error("Exception in revokeEventAppRole:", {
660
- error: err,
661
- errorMessage,
662
- params
663
- });
664
- }
665
- setError(err instanceof Error ? err : new Error(errorMessage));
666
- return {
667
- success: false,
668
- error: errorMessage
669
- };
670
- } finally {
671
- setIsLoading(false);
672
- }
673
- }, [user?.id, supabase]);
674
- const grantEventAppRole = useCallback(async (params) => {
675
- setIsLoading(true);
676
- setError(null);
677
- try {
678
- const { data, error: rpcError } = await supabase.rpc("grant_event_app_role", {
679
- p_user_id: params.user_id,
680
- p_organisation_id: params.organisation_id,
681
- p_event_id: params.event_id,
682
- p_app_id: params.app_id,
683
- p_role: params.role,
684
- p_granted_by: params.granted_by || user?.id || void 0,
685
- p_valid_from: params.valid_from,
686
- p_valid_to: params.valid_to
687
- });
688
- if (rpcError) {
689
- throw new Error(rpcError.message || "Failed to grant role");
690
- }
691
- if (!data) {
692
- return {
693
- success: false,
694
- error: "Failed to grant role - no role ID returned"
695
- };
696
- }
697
- return {
698
- success: true,
699
- message: "Role granted successfully",
700
- roleId: data
701
- };
702
- } catch (err) {
703
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
704
- setError(err instanceof Error ? err : new Error(errorMessage));
705
- return {
706
- success: false,
707
- error: errorMessage
708
- };
709
- } finally {
710
- setIsLoading(false);
711
- }
712
- }, [user?.id, supabase]);
713
- const revokeRoleById = useCallback(async (roleId) => {
714
- setIsLoading(true);
715
- setError(null);
716
- try {
717
- const { data: roleData, error: fetchError } = await supabase.from("rbac_event_app_roles").select("user_id, role, event_id, app_id").eq("id", roleId).single();
718
- if (fetchError || !roleData) {
719
- throw new Error(fetchError?.message || "Role not found");
720
- }
721
- const contextId = `${roleData.event_id}:${roleData.app_id}`;
722
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
723
- p_user_id: roleData.user_id,
724
- p_role_type: "event_app",
725
- p_role_name: roleData.role,
726
- p_context_id: contextId,
727
- p_revoked_by: user?.id || void 0
728
- });
729
- if (rpcError) {
730
- const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
731
- throw new Error(errorMessage);
732
- }
733
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
734
- if (!result) {
735
- return {
736
- success: false,
737
- error: void 0
738
- };
923
+ const runWithLoading = useCallback(
924
+ async (fn) => {
925
+ setIsLoading(true);
926
+ setError(null);
927
+ try {
928
+ return await fn();
929
+ } catch (err) {
930
+ setError(err instanceof Error ? err : new Error(String(err)));
931
+ throw err;
932
+ } finally {
933
+ setIsLoading(false);
739
934
  }
740
- if (result.success === false) {
741
- const errorMessage = result.message || result.error_code || "Role revocation failed";
742
- return {
743
- success: false,
744
- message: result.message || void 0,
745
- error: errorMessage
746
- };
935
+ },
936
+ []
937
+ );
938
+ const revokeEventAppRole = useCallback(
939
+ async (params) => {
940
+ try {
941
+ return await runWithLoading(
942
+ () => revokeEventAppRoleRpc(supabase, params, user?.id)
943
+ );
944
+ } catch (err) {
945
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
946
+ return failureResult(msg);
747
947
  }
748
- return {
749
- success: true,
750
- message: result.message || "Role revoked successfully",
751
- error: void 0
752
- };
753
- } catch (err) {
754
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
755
- setError(err instanceof Error ? err : new Error(errorMessage));
756
- return {
757
- success: false,
758
- error: errorMessage
759
- };
760
- } finally {
761
- setIsLoading(false);
762
- }
763
- }, [user?.id, supabase]);
764
- const grantGlobalRole = useCallback(async (params) => {
765
- setIsLoading(true);
766
- setError(null);
767
- try {
768
- const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", {
769
- p_user_id: params.user_id,
770
- p_role_type: "global",
771
- p_role_name: params.role,
772
- p_context_id: null,
773
- // Global roles don't need context
774
- p_granted_by: params.granted_by || user?.id || void 0
775
- });
776
- if (rpcError) {
777
- throw new Error(rpcError.message || "Failed to grant role");
948
+ },
949
+ [supabase, user?.id, runWithLoading]
950
+ );
951
+ const grantEventAppRole = useCallback(
952
+ async (params) => {
953
+ try {
954
+ return await runWithLoading(
955
+ () => grantEventAppRoleRpc(supabase, params, user?.id)
956
+ );
957
+ } catch (err) {
958
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
959
+ return failureResult(msg);
778
960
  }
779
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
780
- if (!result || !result.success) {
781
- return {
782
- success: false,
783
- error: result?.message || result?.error_code || "Failed to grant role",
784
- message: result?.message
785
- };
961
+ },
962
+ [supabase, user?.id, runWithLoading]
963
+ );
964
+ const revokeRoleById = useCallback(
965
+ async (roleId) => {
966
+ try {
967
+ return await runWithLoading(
968
+ () => revokeRoleByIdRpc(supabase, roleId, user?.id)
969
+ );
970
+ } catch (err) {
971
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
972
+ return failureResult(msg);
786
973
  }
787
- return {
788
- success: true,
789
- message: result.message || "Role granted successfully",
790
- roleId: result.role_id
791
- };
792
- } catch (err) {
793
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
794
- setError(err instanceof Error ? err : new Error(errorMessage));
795
- return {
796
- success: false,
797
- error: errorMessage
798
- };
799
- } finally {
800
- setIsLoading(false);
801
- }
802
- }, [user?.id, supabase]);
803
- const revokeGlobalRole = useCallback(async (params) => {
804
- setIsLoading(true);
805
- setError(null);
806
- try {
807
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
808
- p_user_id: params.user_id,
809
- p_role_type: "global",
810
- p_role_name: params.role,
811
- p_context_id: null,
812
- // Global roles don't need context
813
- p_revoked_by: params.revoked_by || user?.id || void 0
814
- });
815
- if (rpcError) {
816
- const errorParts = [
817
- rpcError.message,
818
- rpcError.details,
819
- rpcError.hint,
820
- rpcError.code ? `Error code: ${rpcError.code}` : null
821
- ].filter(Boolean);
822
- const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
823
- throw new Error(errorMessage);
974
+ },
975
+ [supabase, user?.id, runWithLoading]
976
+ );
977
+ const grantGlobalRole = useCallback(
978
+ async (params) => {
979
+ try {
980
+ return await runWithLoading(
981
+ () => grantGlobalRoleRpc(supabase, params, user?.id)
982
+ );
983
+ } catch (err) {
984
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
985
+ return failureResult(msg);
824
986
  }
825
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
826
- return {
827
- success: result?.success === true,
828
- message: result?.message || void 0,
829
- error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
830
- };
831
- } catch (err) {
832
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
833
- setError(err instanceof Error ? err : new Error(errorMessage));
834
- return {
835
- success: false,
836
- error: errorMessage
837
- };
838
- } finally {
839
- setIsLoading(false);
840
- }
841
- }, [user?.id, supabase]);
842
- const grantOrganisationRole = useCallback(async (params) => {
843
- setIsLoading(true);
844
- setError(null);
845
- try {
846
- const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", {
847
- p_user_id: params.user_id,
848
- p_role_type: "organisation",
849
- p_role_name: params.role,
850
- p_context_id: params.organisation_id,
851
- // Organisation ID as context
852
- p_granted_by: params.granted_by || user?.id || void 0
853
- });
854
- if (rpcError) {
855
- throw new Error(rpcError.message || "Failed to grant role");
987
+ },
988
+ [supabase, user?.id, runWithLoading]
989
+ );
990
+ const revokeGlobalRole = useCallback(
991
+ async (params) => {
992
+ try {
993
+ return await runWithLoading(
994
+ () => revokeGlobalRoleRpc(supabase, params, user?.id)
995
+ );
996
+ } catch (err) {
997
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
998
+ return failureResult(msg);
856
999
  }
857
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
858
- if (!result || !result.success) {
859
- return {
860
- success: false,
861
- error: result?.message || result?.error_code || "Failed to grant role",
862
- message: result?.message
863
- };
1000
+ },
1001
+ [supabase, user?.id, runWithLoading]
1002
+ );
1003
+ const grantOrganisationRole = useCallback(
1004
+ async (params) => {
1005
+ try {
1006
+ return await runWithLoading(
1007
+ () => grantOrganisationRoleRpc(supabase, params, user?.id)
1008
+ );
1009
+ } catch (err) {
1010
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
1011
+ return failureResult(msg);
864
1012
  }
865
- return {
866
- success: true,
867
- message: result.message || "Role granted successfully",
868
- roleId: result.role_id
869
- };
870
- } catch (err) {
871
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
872
- setError(err instanceof Error ? err : new Error(errorMessage));
873
- return {
874
- success: false,
875
- error: errorMessage
876
- };
877
- } finally {
878
- setIsLoading(false);
879
- }
880
- }, [user?.id, supabase]);
881
- const revokeOrganisationRole = useCallback(async (params) => {
882
- setIsLoading(true);
883
- setError(null);
884
- try {
885
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
886
- p_user_id: params.user_id,
887
- p_role_type: "organisation",
888
- p_role_name: params.role,
889
- p_context_id: params.organisation_id,
890
- // Organisation ID as context
891
- p_revoked_by: params.revoked_by || user?.id || void 0
892
- });
893
- if (rpcError) {
894
- const errorParts = [
895
- rpcError.message,
896
- rpcError.details,
897
- rpcError.hint,
898
- rpcError.code ? `Error code: ${rpcError.code}` : null
899
- ].filter(Boolean);
900
- const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
901
- throw new Error(errorMessage);
1013
+ },
1014
+ [supabase, user?.id, runWithLoading]
1015
+ );
1016
+ const revokeOrganisationRole = useCallback(
1017
+ async (params) => {
1018
+ try {
1019
+ return await runWithLoading(
1020
+ () => revokeOrganisationRoleRpc(supabase, params, user?.id)
1021
+ );
1022
+ } catch (err) {
1023
+ const msg = err instanceof Error ? err.message : "Unknown error occurred";
1024
+ return failureResult(msg);
902
1025
  }
903
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
904
- return {
905
- success: result?.success === true,
906
- message: result?.message || void 0,
907
- error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
908
- };
909
- } catch (err) {
910
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
911
- setError(err instanceof Error ? err : new Error(errorMessage));
912
- return {
913
- success: false,
914
- error: errorMessage
915
- };
916
- } finally {
917
- setIsLoading(false);
918
- }
919
- }, [user?.id, supabase]);
1026
+ },
1027
+ [supabase, user?.id, runWithLoading]
1028
+ );
920
1029
  return {
921
- // Event app roles (existing)
922
1030
  revokeEventAppRole,
923
1031
  grantEventAppRole,
924
1032
  revokeRoleById,
925
- // Global roles (new)
926
1033
  grantGlobalRole,
927
1034
  revokeGlobalRole,
928
- // Organisation roles (new)
929
1035
  grantOrganisationRole,
930
1036
  revokeOrganisationRole,
931
- // Shared state
932
1037
  isLoading,
933
1038
  error
934
1039
  };
@@ -945,14 +1050,17 @@ function withPermissionGuard(config, handler) {
945
1050
  if (!userId || !organisationId) {
946
1051
  throw new Error("User context required for permission check");
947
1052
  }
948
- const { isPermitted: isPermitted2 } = await import('./api-F47QJ7FX.js');
949
- const hasPermission = await isPermitted2({
1053
+ const { isPermitted: isPermitted2 } = await import('./api-BZR2CYXL.js');
1054
+ const result = await isPermitted2({
950
1055
  userId,
951
1056
  scope: { organisationId, eventId, appId },
952
1057
  permission: config.permission,
953
1058
  pageId: config.pageId
954
1059
  });
955
- if (!hasPermission) {
1060
+ if (!result.ok) {
1061
+ throw new Error(result.error.message);
1062
+ }
1063
+ if (!result.data) {
956
1064
  throw new Error(`Permission denied: ${config.permission}`);
957
1065
  }
958
1066
  return handler(...args);
@@ -968,11 +1076,15 @@ function withAccessLevelGuard(minLevel, handler) {
968
1076
  if (!userId || !organisationId) {
969
1077
  throw new Error("User context required for access level check");
970
1078
  }
971
- const { getAccessLevel: getAccessLevel2 } = await import('./api-F47QJ7FX.js');
972
- const accessLevel = await getAccessLevel2({
1079
+ const { getAccessLevel: getAccessLevel2 } = await import('./api-BZR2CYXL.js');
1080
+ const result = await getAccessLevel2({
973
1081
  userId,
974
1082
  scope: { organisationId, eventId, appId }
975
1083
  });
1084
+ if (!result.ok) {
1085
+ throw new Error(result.error.message);
1086
+ }
1087
+ const accessLevel = result.data;
976
1088
  const levelHierarchy = ["viewer", "participant", "planner", "admin", "super"];
977
1089
  const userLevelIndex = levelHierarchy.indexOf(accessLevel);
978
1090
  const requiredLevelIndex = levelHierarchy.indexOf(minLevel);
@@ -993,11 +1105,11 @@ function withRoleGuard(config, handler) {
993
1105
  throw new Error("User context required for role check");
994
1106
  }
995
1107
  if (config.globalRoles && config.globalRoles.length > 0) {
996
- const { isSuperAdmin: isSuperAdmin2 } = await import('./api-F47QJ7FX.js');
997
- const isSuper = await isSuperAdmin2(userId);
998
- if (isSuper) {
1108
+ const { isSuperAdmin: isSuperAdmin2 } = await import('./api-BZR2CYXL.js');
1109
+ const superResult = await isSuperAdmin2(userId);
1110
+ if (superResult.ok && superResult.data) {
999
1111
  if (organisationId) {
1000
- const { emitAuditEvent: emitAuditEvent2 } = await import('./audit-Z6ZZBWLU.js');
1112
+ const { emitAuditEvent: emitAuditEvent2 } = await import('./audit-HI2DHUVU.js');
1001
1113
  await emitAuditEvent2({
1002
1114
  type: "permission_check",
1003
1115
  userId,
@@ -1019,21 +1131,27 @@ function withRoleGuard(config, handler) {
1019
1131
  }
1020
1132
  }
1021
1133
  if (config.organisationRoles && config.organisationRoles.length > 0) {
1022
- const { isOrganisationAdmin } = await import('./api-F47QJ7FX.js');
1023
- const isOrgAdmin = await isOrganisationAdmin(userId, organisationId);
1024
- if (!isOrgAdmin && config.requireAll !== false) {
1134
+ const { isOrganisationAdmin } = await import('./api-BZR2CYXL.js');
1135
+ const orgResult = await isOrganisationAdmin(userId, organisationId);
1136
+ if (!orgResult.ok) {
1137
+ throw new Error(orgResult.error.message);
1138
+ }
1139
+ if (!orgResult.data && config.requireAll !== false) {
1025
1140
  throw new Error(`Organisation admin role required`);
1026
1141
  }
1027
1142
  }
1028
1143
  if (config.eventAppRoles && config.eventAppRoles.length > 0 && eventId && appId) {
1029
- const { isEventAdmin } = await import('./api-F47QJ7FX.js');
1030
- const isEventAdminUser = await isEventAdmin(userId, { organisationId, eventId, appId });
1031
- if (!isEventAdminUser && config.requireAll !== false) {
1144
+ const { isEventAdmin } = await import('./api-BZR2CYXL.js');
1145
+ const eventResult = await isEventAdmin(userId, { organisationId, eventId, appId });
1146
+ if (!eventResult.ok) {
1147
+ throw new Error(eventResult.error.message);
1148
+ }
1149
+ if (!eventResult.data && config.requireAll !== false) {
1032
1150
  throw new Error(`Event admin role required`);
1033
1151
  }
1034
1152
  }
1035
1153
  if (organisationId) {
1036
- const { emitAuditEvent: emitAuditEvent2 } = await import('./audit-Z6ZZBWLU.js');
1154
+ const { emitAuditEvent: emitAuditEvent2 } = await import('./audit-HI2DHUVU.js');
1037
1155
  await emitAuditEvent2({
1038
1156
  type: "permission_check",
1039
1157
  userId,
@@ -1066,14 +1184,14 @@ function createRBACMiddleware(config) {
1066
1184
  );
1067
1185
  if (protectedRoute) {
1068
1186
  try {
1069
- const { isPermitted: isPermitted2 } = await import('./api-F47QJ7FX.js');
1070
- const hasPermission = await isPermitted2({
1187
+ const { isPermitted: isPermitted2 } = await import('./api-BZR2CYXL.js');
1188
+ const result = await isPermitted2({
1071
1189
  userId,
1072
1190
  scope: { organisationId },
1073
1191
  permission: protectedRoute.permission,
1074
1192
  pageId: protectedRoute.pageId
1075
1193
  });
1076
- if (!hasPermission) {
1194
+ if (!result.ok || !result.data) {
1077
1195
  return res.redirect(config.fallbackUrl || "/access-denied");
1078
1196
  }
1079
1197
  } catch (_error) {
@@ -1093,14 +1211,14 @@ function createRBACExpressMiddleware(config) {
1093
1211
  return res.status(401).json({ error: "User context required" });
1094
1212
  }
1095
1213
  try {
1096
- const { isPermitted: isPermitted2 } = await import('./api-F47QJ7FX.js');
1097
- const hasPermission = await isPermitted2({
1214
+ const { isPermitted: isPermitted2 } = await import('./api-BZR2CYXL.js');
1215
+ const result = await isPermitted2({
1098
1216
  userId,
1099
1217
  scope: { organisationId, eventId, appId },
1100
1218
  permission: config.permission,
1101
1219
  pageId: config.pageId
1102
1220
  });
1103
- if (!hasPermission) {
1221
+ if (!result.ok || !result.data) {
1104
1222
  return res.status(403).json({ error: "Permission denied" });
1105
1223
  }
1106
1224
  next();