@jmruthers/pace-core 0.6.9 → 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 (1182) 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 +74 -2
  5. package/audit-tool/audits/03-architecture.cjs +220 -20
  6. package/audit-tool/audits/04-code-quality.cjs +95 -3
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +214 -25
  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 +3 -26
  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 +120 -8
  19. package/cursor-rules/06-security-rbac.mdc +126 -2
  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-EFYP2QLE.js +16 -0
  24. package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
  25. package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
  26. package/dist/api-BZR2CYXL.js +5 -0
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/assets/app-icons/admin_favicon.svg +462 -0
  29. package/dist/assets/app-icons/base_favicon.svg +85 -0
  30. package/dist/assets/app-icons/cake_favicon.svg +68 -0
  31. package/dist/assets/app-icons/core_favicon.svg +256 -0
  32. package/dist/assets/app-icons/gear_favicon.svg +91 -0
  33. package/dist/assets/app-icons/medi_favicon.svg +92 -0
  34. package/dist/assets/app-icons/mint_favicon.svg +83 -0
  35. package/dist/assets/app-icons/pace_favicon.svg +49 -0
  36. package/dist/assets/app-icons/pump_favicon.svg +68 -0
  37. package/dist/assets/app-icons/seed_favicon.svg +91 -0
  38. package/dist/assets/app-icons/team_favicon.svg +67 -0
  39. package/dist/assets/app-icons/trac_favicon.svg +112 -0
  40. package/dist/assets/app-icons/trip_favicon.svg +102 -0
  41. package/dist/audit-HI2DHUVU.js +4 -0
  42. package/dist/auth-JvdRVaud.d.ts +49 -0
  43. package/dist/chunk-2DL2WSOE.js +327 -0
  44. package/dist/chunk-2OEVOGGR.js +9598 -0
  45. package/dist/chunk-44CNXN4P.js +15 -0
  46. package/dist/chunk-4R3T5ENU.js +2943 -0
  47. package/dist/chunk-7A6IMHH2.js +2321 -0
  48. package/dist/chunk-BTHN5MKC.js +121 -0
  49. package/dist/chunk-CU2BU2MQ.js +2 -0
  50. package/dist/chunk-D6BMFMQZ.js +200 -0
  51. package/dist/chunk-DDMPHZ3D.js +58 -0
  52. package/dist/chunk-ENLXB7GP.js +721 -0
  53. package/dist/chunk-J2KQK6DG.js +2159 -0
  54. package/dist/chunk-KJXRL3XE.js +6434 -0
  55. package/dist/chunk-L5LFKKLJ.js +61 -0
  56. package/dist/chunk-PCSHBLPB.js +811 -0
  57. package/dist/chunk-QRYSEPHB.js +429 -0
  58. package/dist/chunk-RMLY6KB5.js +187 -0
  59. package/dist/chunk-SACF5YSM.js +31 -0
  60. package/dist/chunk-UZNAFKGW.js +125 -0
  61. package/dist/chunk-V7FTM2LU.js +1080 -0
  62. package/dist/chunk-WY6Y7KC3.js +264 -0
  63. package/dist/chunk-XOJME5T7.js +407 -0
  64. package/dist/chunk-XPFVT3GN.js +492 -0
  65. package/dist/chunk-YFTFFJIV.js +529 -0
  66. package/dist/chunk-YYTWKVHO.js +1334 -0
  67. package/dist/components.d.ts +12 -89
  68. package/dist/components.js +23 -55
  69. package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
  70. package/dist/eslint-rules/index.cjs +3 -0
  71. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  72. package/dist/eslint-rules/rules/05-styling.cjs +507 -0
  73. package/dist/eslint-rules/rules/06-security-rbac.cjs +84 -0
  74. package/dist/event-BfCox3N2.d.ts +265 -0
  75. package/dist/file-reference-DU1hcawx.d.ts +164 -0
  76. package/dist/functions-DH45k8ec.d.ts +208 -0
  77. package/dist/hooks.d.ts +28 -14
  78. package/dist/hooks.js +90 -56
  79. package/dist/icons/index.d.ts +1 -0
  80. package/dist/icons/index.js +1 -0
  81. package/dist/index.d.ts +392 -155
  82. package/dist/index.js +337 -347
  83. package/dist/pagination-BW1mqywp.d.ts +201 -0
  84. package/dist/papaparseLoader-WG2UXQ22.js +7 -0
  85. package/dist/providers.d.ts +29 -14
  86. package/dist/providers.js +7 -5
  87. package/dist/rbac/eslint-rules.js +2 -2
  88. package/dist/rbac/index.d.ts +180 -351
  89. package/dist/rbac/index.js +13 -11
  90. package/dist/theming/runtime.d.ts +28 -5
  91. package/dist/theming/runtime.js +2 -2
  92. package/dist/timezone-BTWWXKVY.d.ts +696 -0
  93. package/dist/types-BE2sEHKd.d.ts +55 -0
  94. package/dist/types-CvOPXWWZ.d.ts +111 -0
  95. package/dist/types-Dr8sNhER.d.ts +50 -0
  96. package/dist/types.d.ts +20 -13
  97. package/dist/types.js +1 -0
  98. package/dist/usePublicPageContext-B91dGYW1.d.ts +4367 -0
  99. package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
  100. package/dist/utils.d.ts +338 -156
  101. package/dist/utils.js +78 -60
  102. package/dist/validation-g5n0hDkh.d.ts +177 -0
  103. package/docs/api/modules.md +1226 -1094
  104. package/docs/api-reference/components.md +5 -5
  105. package/docs/api-reference/rpc-functions.md +12 -3
  106. package/docs/core-concepts/rbac-system.md +8 -0
  107. package/docs/getting-started/cursor-rules.md +17 -20
  108. package/docs/getting-started/dependencies.md +1 -1
  109. package/docs/getting-started/setup.md +235 -0
  110. package/docs/implementation-guides/authentication.md +27 -0
  111. package/docs/implementation-guides/data-tables.md +365 -10
  112. package/docs/migration/ApiResult-migration.md +25 -0
  113. package/docs/rbac/RBAC_CONTRACT.md +0 -12
  114. package/docs/rbac/api-reference.md +33 -31
  115. package/docs/standards/0-standards-overview.md +50 -15
  116. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  117. package/docs/standards/2-project-structure-standards.md +45 -90
  118. package/docs/standards/3-architecture-standards.md +41 -1
  119. package/docs/standards/4-code-quality-standards.md +26 -6
  120. package/docs/standards/5-styling-standards.md +35 -1
  121. package/docs/standards/6-security-rbac-standards.md +288 -7
  122. package/docs/standards/7-api-tech-stack-standards.md +116 -17
  123. package/docs/standards/8-testing-documentation-standards.md +31 -0
  124. package/docs/standards/9-operations-standards.md +19 -0
  125. package/docs/standards/README.md +20 -201
  126. package/docs/testing/README.md +10 -0
  127. package/docs/testing/test-setup-for-consumers.md +916 -0
  128. package/docs/troubleshooting/common-issues.md +17 -1
  129. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  130. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  131. package/eslint-config-pace-core.cjs +24 -0
  132. package/package.json +14 -20
  133. package/scripts/build-docs.js +180 -0
  134. package/scripts/setup.cjs +536 -0
  135. package/scripts/validate.cjs +480 -0
  136. package/src/__mocks__/lucide-react.ts +0 -2
  137. package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
  138. package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
  139. package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
  140. package/src/__tests__/helpers/test-providers.test.tsx +99 -0
  141. package/src/__tests__/helpers/test-providers.tsx +37 -39
  142. package/src/__tests__/helpers/test-utils.test.tsx +447 -0
  143. package/src/__tests__/helpers/timer-utils.test.ts +371 -0
  144. package/src/assets/app-icons/admin_favicon.svg +462 -0
  145. package/src/assets/app-icons/base_favicon.svg +85 -0
  146. package/src/assets/app-icons/cake_favicon.svg +68 -0
  147. package/src/assets/app-icons/core_favicon.svg +256 -0
  148. package/src/assets/app-icons/gear_favicon.svg +91 -0
  149. package/src/assets/app-icons/index.test.ts +304 -0
  150. package/src/assets/app-icons/index.ts +83 -0
  151. package/src/assets/app-icons/medi_favicon.svg +92 -0
  152. package/src/assets/app-icons/mint_favicon.svg +83 -0
  153. package/src/assets/app-icons/pace_favicon.svg +49 -0
  154. package/src/assets/app-icons/pump_favicon.svg +68 -0
  155. package/src/assets/app-icons/seed_favicon.svg +91 -0
  156. package/src/assets/app-icons/team_favicon.svg +67 -0
  157. package/src/assets/app-icons/trac_favicon.svg +112 -0
  158. package/src/assets/app-icons/trip_favicon.svg +102 -0
  159. package/src/components/AddressField/AddressField.test.tsx +379 -4
  160. package/src/components/AddressField/AddressField.tsx +239 -213
  161. package/src/components/AddressField/types.ts +2 -2
  162. package/src/components/Alert/Alert.test.tsx +35 -25
  163. package/src/components/Alert/Alert.tsx +8 -8
  164. package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
  165. package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
  166. package/src/components/Avatar/Avatar.test.tsx +11 -1
  167. package/src/components/Avatar/Avatar.tsx +3 -2
  168. package/src/components/Badge/Badge.test.tsx +11 -1
  169. package/src/components/Button/Button.test.tsx +13 -3
  170. package/src/components/Button/Button.tsx +1 -1
  171. package/src/components/Calendar/Calendar.test.tsx +523 -131
  172. package/src/components/Calendar/Calendar.tsx +107 -488
  173. package/src/components/Card/Card.test.tsx +384 -258
  174. package/src/components/Card/Card.tsx +19 -10
  175. package/src/components/Checkbox/Checkbox.test.tsx +58 -174
  176. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  177. package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
  178. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  179. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  180. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  181. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  182. package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
  183. package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
  184. package/src/components/DataTable/DataTable.export.test.tsx +705 -0
  185. package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
  186. package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
  187. package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
  188. package/src/components/DataTable/DataTable.test.tsx +787 -416
  189. package/src/components/DataTable/DataTable.tsx +14 -14
  190. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  191. package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
  192. package/src/components/DataTable/DataTableCore.test.tsx +970 -0
  193. package/src/components/DataTable/README.md +155 -0
  194. package/src/components/DataTable/TESTING.md +101 -0
  195. package/src/components/DataTable/a11y.basic.test.tsx +788 -0
  196. package/src/components/DataTable/components/DataTableCore.tsx +126 -894
  197. package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
  198. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -3
  199. package/src/components/DataTable/components/ImportModal.tsx +82 -408
  200. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  201. package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
  202. package/src/components/DataTable/context/DataTableContext.tsx +13 -13
  203. package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
  204. package/src/components/DataTable/core/ColumnFactory.ts +3 -3
  205. package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
  206. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
  207. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
  208. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
  209. package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
  210. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +15 -3
  211. package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
  212. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  213. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  214. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  215. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  216. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  217. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  218. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  219. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  220. package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
  221. package/src/components/DataTable/hooks/useDataTablePermissions.ts +81 -260
  222. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  223. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  224. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  225. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  226. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  227. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  228. package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
  229. package/src/components/DataTable/hooks/useDataTableState.ts +161 -114
  230. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  231. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  232. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  233. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  234. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  235. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  236. package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
  237. package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
  238. package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
  239. package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
  240. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  241. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  242. package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
  243. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +311 -271
  244. package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
  245. package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
  246. package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
  247. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +27 -4
  248. package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
  249. package/src/components/DataTable/hooks/useTableColumns.ts +15 -39
  250. package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
  251. package/src/components/DataTable/hooks/useTableHandlers.ts +13 -22
  252. package/src/components/DataTable/index.ts +28 -5
  253. package/src/components/DataTable/keyboard.test.tsx +734 -0
  254. package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
  255. package/src/components/DataTable/pagination.modes.test.tsx +728 -0
  256. package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
  257. package/src/components/DataTable/styles.test.ts +379 -0
  258. package/src/components/DataTable/styles.ts +0 -1
  259. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  260. package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
  261. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  262. package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
  263. package/src/components/DataTable/test-utils.ts +94 -0
  264. package/src/components/DataTable/types/actions.ts +71 -0
  265. package/src/components/DataTable/types/base.ts +39 -0
  266. package/src/components/DataTable/types/columns.ts +125 -0
  267. package/src/components/DataTable/types/export.ts +32 -0
  268. package/src/components/DataTable/types/features.ts +81 -0
  269. package/src/components/DataTable/types/hierarchical.ts +44 -0
  270. package/src/components/DataTable/types/index.ts +43 -0
  271. package/src/components/DataTable/types/pagination.ts +85 -0
  272. package/src/components/DataTable/types/performance.ts +47 -0
  273. package/src/components/DataTable/types/props.ts +62 -0
  274. package/src/components/DataTable/types/rbac.ts +45 -0
  275. package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
  276. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  277. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
  278. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
  279. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  280. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  281. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  282. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  283. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  284. package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
  285. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  286. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  287. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  288. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  289. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  290. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  291. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  292. package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
  293. package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
  294. package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
  295. package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
  296. package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
  297. package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
  298. package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
  299. package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
  300. package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
  301. package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
  302. package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
  303. package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
  304. package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
  305. package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
  306. package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
  307. package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
  308. package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
  309. package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
  310. package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
  311. package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
  312. package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
  313. package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
  314. package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
  315. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  316. package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
  317. package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
  318. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
  319. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
  320. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
  321. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
  322. package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
  323. package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
  324. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  325. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  326. package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
  327. package/src/components/DataTable/utils/a11yUtils.ts +1 -1
  328. package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
  329. package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
  330. package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
  331. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  332. package/src/components/DataTable/utils/csvParse.ts +65 -0
  333. package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
  334. package/src/components/DataTable/utils/errorHandling.ts +3 -1
  335. package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
  336. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  337. package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
  338. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  339. package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
  340. package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
  341. package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
  342. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  343. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  344. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  345. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  346. package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
  347. package/src/components/DataTable/utils/paginationUtils.ts +7 -4
  348. package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
  349. package/src/components/DataTable/utils/performanceUtils.ts +1 -1
  350. package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
  351. package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
  352. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -67
  353. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +18 -25
  354. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
  355. package/src/components/DateTimeField/DateTimeField.test.tsx +3 -16
  356. package/src/components/DateTimeField/DateTimeField.tsx +1 -1
  357. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  358. package/src/components/Dialog/Dialog.test.tsx +2865 -458
  359. package/src/components/Dialog/Dialog.tsx +183 -986
  360. package/src/components/Dialog/dialogLock.test.ts +238 -0
  361. package/src/components/Dialog/dialogLock.ts +98 -0
  362. package/src/components/Dialog/index.ts +2 -0
  363. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  364. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  365. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  366. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  367. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  368. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  369. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
  370. package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
  371. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
  372. package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
  373. package/src/components/ErrorBoundary/index.ts +3 -4
  374. package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
  375. package/src/components/FileDisplay/FileDisplay.test.tsx +479 -247
  376. package/src/components/FileDisplay/FileDisplay.tsx +29 -659
  377. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  378. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  379. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  380. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  381. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  382. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  383. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  384. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  385. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  386. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  387. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  388. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  389. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  390. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  391. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  392. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  393. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  394. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  395. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  396. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  397. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  398. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  399. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  400. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  401. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  402. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  403. package/src/components/FileDisplay/index.tsx +1 -1
  404. package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
  405. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  406. package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1438 -0
  407. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  408. package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
  409. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  410. package/src/components/FileUpload/FileUpload.test.tsx +69 -27
  411. package/src/components/FileUpload/FileUpload.tsx +112 -527
  412. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  413. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  414. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  415. package/src/components/FileUpload/index.tsx +1 -1
  416. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  417. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  418. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  419. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  420. package/src/components/Footer/Footer.test.tsx +15 -382
  421. package/src/components/Footer/Footer.tsx +8 -125
  422. package/src/components/Form/Form.test.tsx +425 -88
  423. package/src/components/Form/Form.tsx +91 -299
  424. package/src/components/Form/useFormPersistence.ts +257 -0
  425. package/src/components/Header/Header.test.tsx +653 -163
  426. package/src/components/Header/Header.tsx +62 -44
  427. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
  428. package/src/components/Input/Input.test.tsx +34 -120
  429. package/src/components/Input/Input.tsx +1 -1
  430. package/src/components/Label/Label.test.tsx +46 -45
  431. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +8 -11
  432. package/src/components/LoginForm/LoginForm.test.tsx +0 -1
  433. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  434. package/src/components/NavigationMenu/NavigationMenu.test.tsx +2422 -102
  435. package/src/components/NavigationMenu/NavigationMenu.tsx +62 -362
  436. package/src/components/NavigationMenu/index.ts +6 -1
  437. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  438. package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
  439. package/src/components/NavigationMenu/useNavigationFiltering.ts +199 -308
  440. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  441. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1322 -0
  442. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +50 -49
  443. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
  444. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +103 -85
  445. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +774 -44
  446. package/src/components/PaceAppLayout/PaceAppLayout.tsx +282 -764
  447. package/src/components/PaceAppLayout/README.md +0 -9
  448. package/src/components/PaceAppLayout/test-setup.tsx +15 -9
  449. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  450. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  451. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  452. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  453. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  454. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  455. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  456. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +782 -20
  457. package/src/components/PaceLoginPage/PaceLoginPage.tsx +33 -125
  458. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  459. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
  460. package/src/components/Progress/Progress.test.tsx +127 -1
  461. package/src/components/Progress/Progress.tsx +1 -2
  462. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
  463. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -217
  464. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  465. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  466. package/src/components/PublicLayout/PublicLayout.test.tsx +1640 -38
  467. package/src/components/PublicLayout/PublicPageContext.ts +28 -0
  468. package/src/components/PublicLayout/PublicPageLayout.tsx +134 -75
  469. package/src/components/PublicLayout/PublicPageProvider.tsx +7 -42
  470. package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
  471. package/src/components/Select/Select.test.tsx +45 -8
  472. package/src/components/Select/Select.tsx +57 -40
  473. package/src/components/Select/context.test.tsx +56 -0
  474. package/src/components/Select/text.test.tsx +104 -0
  475. package/src/components/Select/text.ts +26 -0
  476. package/src/components/Select/types.ts +3 -0
  477. package/src/components/Select/useSelectEvents.test.ts +279 -0
  478. package/src/components/Select/useSelectEvents.ts +87 -0
  479. package/src/components/Select/useSelectSearch.test.tsx +295 -0
  480. package/src/components/Select/useSelectSearch.ts +91 -0
  481. package/src/components/Select/useSelectState.test.ts +268 -0
  482. package/src/components/Select/useSelectState.ts +104 -0
  483. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
  484. package/src/components/Switch/Switch.test.tsx +57 -153
  485. package/src/components/Table/Table.test.tsx +395 -317
  486. package/src/components/Tabs/Tabs.test.tsx +270 -0
  487. package/src/components/Tabs/Tabs.tsx +4 -4
  488. package/src/components/Textarea/Textarea.test.tsx +11 -38
  489. package/src/components/Toast/Toast.test.tsx +425 -496
  490. package/src/components/Tooltip/Tooltip.test.tsx +4 -21
  491. package/src/components/UserMenu/UserMenu.test.tsx +1 -21
  492. package/src/components/UserMenu/UserMenu.tsx +0 -1
  493. package/src/components/index.test.ts +346 -0
  494. package/src/components/index.ts +12 -1
  495. package/src/constants/performance.test.ts +91 -0
  496. package/src/hooks/ServiceHooks.test.tsx +725 -0
  497. package/src/hooks/hooks.integration.test.tsx +608 -0
  498. package/src/hooks/index.ts +18 -3
  499. package/src/hooks/index.unit.test.ts +220 -0
  500. package/src/hooks/public/usePublicEvent.test.ts +304 -0
  501. package/src/hooks/public/usePublicEvent.ts +11 -11
  502. package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
  503. package/src/hooks/public/usePublicEventLogo.ts +2 -2
  504. package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
  505. package/src/hooks/public/usePublicRouteParams.ts +2 -2
  506. package/src/hooks/services/useAuth.ts +9 -7
  507. package/src/hooks/services/useAuthService.ts +1 -1
  508. package/src/hooks/services/useEventService.ts +1 -1
  509. package/src/hooks/useAccessibleApps.test.ts +400 -0
  510. package/src/hooks/useAccessibleApps.ts +264 -0
  511. package/src/hooks/useAddressAutocomplete.test.ts +170 -47
  512. package/src/hooks/useAddressAutocomplete.ts +109 -81
  513. package/src/hooks/useApiFetch.unit.test.ts +111 -0
  514. package/src/hooks/useAppConfig.ts +13 -3
  515. package/src/hooks/useAppConfig.unit.test.ts +712 -0
  516. package/src/hooks/useComponentPerformance.unit.test.tsx +314 -0
  517. package/src/hooks/useDataTablePerformance.ts +111 -130
  518. package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
  519. package/src/hooks/useDataTableState.test.ts +170 -0
  520. package/src/hooks/useDataTableState.ts +5 -5
  521. package/src/hooks/useDebounce.unit.test.ts +157 -0
  522. package/src/hooks/useEventTheme.test.ts +70 -18
  523. package/src/hooks/useEventTheme.ts +50 -22
  524. package/src/hooks/useEvents.ts +49 -2
  525. package/src/hooks/useEvents.unit.test.ts +227 -0
  526. package/src/hooks/useFileReference.test.ts +388 -107
  527. package/src/hooks/useFileReference.ts +184 -179
  528. package/src/hooks/useFileUrl.ts +1 -1
  529. package/src/hooks/useFileUrl.unit.test.ts +686 -0
  530. package/src/hooks/useFileUrlCache.test.ts +319 -0
  531. package/src/hooks/useFileUrlCache.ts +5 -2
  532. package/src/hooks/useFocusManagement.unit.test.ts +604 -0
  533. package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
  534. package/src/hooks/useFormDialog.test.ts +307 -0
  535. package/src/hooks/useFormDialog.ts +2 -2
  536. package/src/hooks/useInactivityTracker.ts +141 -134
  537. package/src/hooks/useInactivityTracker.unit.test.ts +446 -0
  538. package/src/hooks/useIsMobile.unit.test.ts +317 -0
  539. package/src/hooks/useIsPrint.ts +62 -0
  540. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  541. package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
  542. package/src/hooks/useOrganisationPermissions.test.ts +1 -2
  543. package/src/hooks/useOrganisationPermissions.ts +1 -4
  544. package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
  545. package/src/hooks/useOrganisationSecurity.test.ts +4 -33
  546. package/src/hooks/useOrganisationSecurity.ts +192 -203
  547. package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
  548. package/src/hooks/useOrganisations.ts +1 -1
  549. package/src/hooks/useOrganisations.unit.test.ts +369 -0
  550. package/src/hooks/usePerformanceMonitor.ts +1 -1
  551. package/src/hooks/usePerformanceMonitor.unit.test.ts +693 -0
  552. package/src/hooks/usePermissionCache.test.ts +298 -329
  553. package/src/hooks/usePermissionCache.ts +277 -276
  554. package/src/hooks/usePreventTabReload.test.ts +307 -0
  555. package/src/hooks/usePublicEvent.simple.test.ts +794 -0
  556. package/src/hooks/usePublicEvent.test.ts +670 -0
  557. package/src/hooks/usePublicEvent.unit.test.ts +638 -0
  558. package/src/hooks/usePublicFileDisplay.test.ts +948 -0
  559. package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
  560. package/src/hooks/useQueryCache.test.ts +391 -0
  561. package/src/hooks/useQueryCache.ts +7 -9
  562. package/src/hooks/useRBAC.unit.test.ts +253 -0
  563. package/src/hooks/useSessionDraft.test.ts +556 -0
  564. package/src/hooks/useSessionDraft.ts +14 -11
  565. package/src/hooks/useSessionRestoration.ts +1 -1
  566. package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
  567. package/src/hooks/useStorage.ts +94 -54
  568. package/src/hooks/useStorage.unit.test.ts +684 -0
  569. package/src/hooks/useToast.test.ts +413 -0
  570. package/src/hooks/useToast.ts +2 -2
  571. package/src/hooks/useToast.unit.test.tsx +481 -0
  572. package/src/hooks/useZodForm.ts +3 -3
  573. package/src/hooks/useZodForm.unit.test.tsx +191 -0
  574. package/src/icons/index.test.ts +133 -0
  575. package/src/icons/index.ts +3 -1
  576. package/src/index.test.ts +528 -0
  577. package/src/index.ts +56 -9
  578. package/src/providers/AuthProvider.test.tsx +218 -0
  579. package/src/providers/EventProvider.test.tsx +487 -0
  580. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  581. package/src/providers/InactivityProvider.test.tsx +421 -0
  582. package/src/providers/ProviderLifecycle.test.tsx +308 -0
  583. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
  584. package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
  585. package/src/providers/index.test.ts +138 -0
  586. package/src/providers/services/AuthServiceContext.ts +27 -0
  587. package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
  588. package/src/providers/services/AuthServiceProvider.test.tsx +638 -0
  589. package/src/providers/services/AuthServiceProvider.tsx +81 -20
  590. package/src/providers/services/EventServiceContext.ts +25 -0
  591. package/src/providers/services/EventServiceProvider.test.tsx +839 -0
  592. package/src/providers/services/EventServiceProvider.tsx +11 -20
  593. package/src/providers/services/InactivityServiceContext.ts +25 -0
  594. package/src/providers/services/InactivityServiceProvider.test.tsx +662 -0
  595. package/src/providers/services/InactivityServiceProvider.tsx +7 -17
  596. package/src/providers/services/OrganisationServiceContext.ts +25 -0
  597. package/src/providers/services/OrganisationServiceProvider.test.tsx +440 -0
  598. package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
  599. package/src/providers/services/UnifiedAuthContext.ts +102 -0
  600. package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
  601. package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
  602. package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
  603. package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
  604. package/src/providers/services/UnifiedAuthProvider.tsx +147 -497
  605. package/src/providers/services/contexts.test.tsx +281 -0
  606. package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
  607. package/src/providers/services/useUnifiedAuth.ts +29 -0
  608. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  609. package/src/providers/useInactivity.test-helper.ts +27 -0
  610. package/src/rbac/README.md +5 -5
  611. package/src/rbac/adapters.comprehensive.test.tsx +429 -0
  612. package/src/rbac/adapters.test.tsx +654 -0
  613. package/src/rbac/adapters.tsx +53 -38
  614. package/src/rbac/api.test.ts +986 -259
  615. package/src/rbac/api.ts +260 -216
  616. package/src/rbac/audit-batched.test.ts +550 -0
  617. package/src/rbac/audit-batched.ts +5 -4
  618. package/src/rbac/audit.test.ts +225 -28
  619. package/src/rbac/audit.ts +26 -18
  620. package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
  621. package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
  622. package/src/rbac/cache-invalidation.test.ts +715 -0
  623. package/src/rbac/cache-invalidation.ts +18 -15
  624. package/src/rbac/cache.test.ts +123 -63
  625. package/src/rbac/cache.ts +3 -4
  626. package/src/rbac/components/AccessDenied.test.tsx +324 -0
  627. package/src/rbac/components/AccessDenied.tsx +20 -18
  628. package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
  629. package/src/rbac/components/NavigationGuard.tsx +10 -8
  630. package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
  631. package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
  632. package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
  633. package/src/rbac/components/PagePermissionGuard.test.tsx +1430 -0
  634. package/src/rbac/components/PagePermissionGuard.tsx +188 -381
  635. package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
  636. package/src/rbac/config.test.ts +131 -48
  637. package/src/rbac/config.ts +69 -26
  638. package/src/rbac/docs/event-based-apps.md +26 -13
  639. package/src/rbac/engine.comprehensive.test.ts +808 -0
  640. package/src/rbac/engine.test.ts +974 -130
  641. package/src/rbac/engine.ts +53 -13
  642. package/src/rbac/errors.test.ts +99 -87
  643. package/src/rbac/errors.ts +89 -55
  644. package/src/rbac/eslint-rules.js +2 -2
  645. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  646. package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
  647. package/src/rbac/hooks/permissions/useAccessLevel.ts +23 -14
  648. package/src/rbac/hooks/permissions/useCan.test.ts +798 -0
  649. package/src/rbac/hooks/permissions/useCan.ts +173 -253
  650. package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
  651. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +63 -10
  652. package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
  653. package/src/rbac/hooks/permissions/usePermissions.ts +50 -78
  654. package/src/rbac/hooks/useCan.test.ts +348 -32
  655. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  656. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  657. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  658. package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
  659. package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
  660. package/src/rbac/hooks/usePermissions.test.ts +459 -33
  661. package/src/rbac/hooks/usePermissions.ts +5 -7
  662. package/src/rbac/hooks/useRBAC.test.ts +1784 -21
  663. package/src/rbac/hooks/useRBAC.ts +148 -88
  664. package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
  665. package/src/rbac/hooks/useResolvedScope.ts +4 -1
  666. package/src/rbac/hooks/useResourcePermissions.test.ts +561 -24
  667. package/src/rbac/hooks/useResourcePermissions.ts +76 -140
  668. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  669. package/src/rbac/hooks/useRoleManagement.test.ts +634 -61
  670. package/src/rbac/hooks/useRoleManagement.ts +158 -586
  671. package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
  672. package/src/rbac/hooks/useSecureSupabase.ts +21 -14
  673. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  674. package/src/rbac/index.test.ts +107 -0
  675. package/src/rbac/index.ts +32 -32
  676. package/src/rbac/performance.test.ts +451 -0
  677. package/src/rbac/permissions.test.ts +149 -68
  678. package/src/rbac/permissions.ts +0 -3
  679. package/src/rbac/rbac-core.test.tsx +276 -0
  680. package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
  681. package/src/rbac/rbac-engine-simplified.test.ts +252 -0
  682. package/src/rbac/rbac-functions.test.ts +703 -0
  683. package/src/rbac/rbac-integration.test.ts +523 -0
  684. package/src/rbac/rbac-role-isolation.test.ts +456 -0
  685. package/src/rbac/request-deduplication.test.ts +352 -0
  686. package/src/rbac/request-deduplication.ts +5 -4
  687. package/src/rbac/scenarios.user-role.test.tsx +271 -0
  688. package/src/rbac/secureClient.test.ts +499 -115
  689. package/src/rbac/secureClient.ts +54 -28
  690. package/src/rbac/security.test.ts +448 -44
  691. package/src/rbac/security.ts +7 -6
  692. package/src/rbac/types/roleManagement.ts +66 -0
  693. package/src/rbac/types.test.ts +236 -0
  694. package/src/rbac/types.ts +7 -5
  695. package/src/rbac/utils/clientSecurity.test.ts +192 -0
  696. package/src/rbac/utils/clientSecurity.ts +6 -4
  697. package/src/rbac/utils/contextValidator.test.ts +126 -0
  698. package/src/rbac/utils/contextValidator.ts +6 -3
  699. package/src/rbac/utils/deep-equal.test.ts +76 -0
  700. package/src/rbac/utils/eventContext.test.ts +401 -0
  701. package/src/rbac/utils/eventContext.ts +38 -34
  702. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  703. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  704. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  705. package/src/services/AuthService.edge-cases.test.ts +746 -0
  706. package/src/services/AuthService.restoreSession.test.ts +59 -0
  707. package/src/services/AuthService.test.ts +1362 -0
  708. package/src/services/AuthService.ts +197 -216
  709. package/src/services/BaseService.edge-cases.test.ts +506 -0
  710. package/src/services/BaseService.test.ts +363 -0
  711. package/src/services/EventService.edge-cases.test.ts +636 -0
  712. package/src/services/EventService.eventColours.test.ts +64 -0
  713. package/src/services/EventService.test.ts +1250 -0
  714. package/src/services/EventService.ts +244 -315
  715. package/src/services/InactivityService.edge-cases.test.ts +492 -0
  716. package/src/services/InactivityService.lifecycle.test.ts +406 -0
  717. package/src/services/InactivityService.test.ts +829 -0
  718. package/src/services/InactivityService.ts +172 -213
  719. package/src/services/OrganisationService.edge-cases.test.ts +633 -0
  720. package/src/services/OrganisationService.pagination.test.ts +409 -0
  721. package/src/services/OrganisationService.test.ts +1579 -0
  722. package/src/services/OrganisationService.ts +186 -257
  723. package/src/services/base/BaseService.test.ts +214 -0
  724. package/src/services/interfaces/IAuthService.test.ts +184 -0
  725. package/src/services/interfaces/IAuthService.ts +10 -9
  726. package/src/services/interfaces/IEventService.test.ts +176 -0
  727. package/src/services/interfaces/IInactivityService.test.ts +183 -0
  728. package/src/services/interfaces/IOrganisationService.test.ts +207 -0
  729. package/src/services/interfaces/IOrganisationService.ts +0 -1
  730. package/src/styles/core.css +244 -12
  731. package/src/theming/parseEventColours.test.ts +321 -0
  732. package/src/theming/parseEventColours.ts +18 -9
  733. package/src/theming/runtime.test.ts +495 -0
  734. package/src/theming/runtime.ts +72 -7
  735. package/src/types/api-result.ts +53 -0
  736. package/src/types/auth.ts +0 -1
  737. package/src/types/core.test.ts +397 -0
  738. package/src/types/database-generated.test.ts +78 -0
  739. package/src/types/database.generated.ts +45 -10
  740. package/src/types/event.ts +39 -19
  741. package/src/types/file-reference.test.ts +351 -0
  742. package/src/types/file-reference.ts +37 -12
  743. package/src/types/guards.test.ts +246 -0
  744. package/src/types/index.test.ts +265 -0
  745. package/src/types/index.ts +3 -0
  746. package/src/types/organisation.roles.test.ts +55 -0
  747. package/src/types/organisation.test.ts +1105 -0
  748. package/src/types/organisation.ts +15 -15
  749. package/src/types/rpc-responses.ts +33 -0
  750. package/src/types/supabase.ts +14 -6
  751. package/src/types/theme.test.ts +830 -0
  752. package/src/types/type-validation.test.ts +526 -0
  753. package/src/types/validation.test.ts +729 -0
  754. package/src/types/vitest-globals.d.ts +1 -1
  755. package/src/utils/app/appConfig.test.ts +235 -0
  756. package/src/utils/app/appIdResolver.test.ts +252 -57
  757. package/src/utils/app/appIdResolver.ts +31 -20
  758. package/src/utils/app/appNameResolver.test.ts +18 -10
  759. package/src/utils/app/appNameResolver.ts +11 -9
  760. package/src/utils/app/appPortMap.test.ts +125 -0
  761. package/src/utils/app/appPortMap.ts +51 -0
  762. package/src/utils/app/buildAppUrl.test.ts +273 -0
  763. package/src/utils/app/buildAppUrl.ts +114 -0
  764. package/src/utils/appConfig.unit.test.ts +55 -0
  765. package/src/utils/audit/audit.test.ts +354 -39
  766. package/src/utils/audit.unit.test.ts +69 -0
  767. package/src/utils/auth-utils.unit.test.ts +69 -0
  768. package/src/utils/bundleAnalysis.unit.test.ts +326 -0
  769. package/src/utils/cn.unit.test.ts +34 -0
  770. package/src/utils/context/organisationContext.test.ts +115 -95
  771. package/src/utils/context/organisationContext.ts +32 -43
  772. package/src/utils/context/sessionTracking.test.ts +354 -0
  773. package/src/utils/core/cn.test.ts +66 -0
  774. package/src/utils/core/debugLogger.test.ts +113 -0
  775. package/src/utils/core/debugLogger.ts +15 -8
  776. package/src/utils/core/logger.test.ts +217 -0
  777. package/src/utils/core/logger.ts +20 -16
  778. package/src/utils/core/mergeRefs.ts +24 -0
  779. package/src/utils/debugLogger.test.ts +417 -0
  780. package/src/utils/device/deviceFingerprint.test.ts +8 -5
  781. package/src/utils/device/deviceFingerprint.ts +3 -3
  782. package/src/utils/deviceFingerprint.unit.test.ts +818 -0
  783. package/src/utils/dynamic/createLazyComponent.tsx +46 -0
  784. package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
  785. package/src/utils/dynamic/dynamicUtils.ts +6 -6
  786. package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
  787. package/src/utils/dynamic/lazyLoad.tsx +8 -36
  788. package/src/utils/dynamic/papaparseLoader.ts +7 -0
  789. package/src/utils/dynamicUtils.unit.test.ts +331 -0
  790. package/src/utils/file-reference/file-reference.test.ts +1238 -0
  791. package/src/utils/file-reference/index.ts +330 -348
  792. package/src/utils/formatDate.unit.test.ts +109 -0
  793. package/src/utils/formatting/formatDate.test.ts +22 -148
  794. package/src/utils/formatting/formatDateTime.test.ts +41 -119
  795. package/src/utils/formatting/formatDateTimeTimezone.test.ts +41 -85
  796. package/src/utils/formatting/formatNumber.test.ts +259 -0
  797. package/src/utils/formatting/formatTime.test.ts +36 -128
  798. package/src/utils/formatting/formatting.ts +1 -1
  799. package/src/utils/formatting.unit.test.ts +99 -0
  800. package/src/utils/google-places/googlePlacesUtils.test.ts +127 -36
  801. package/src/utils/google-places/googlePlacesUtils.ts +67 -86
  802. package/src/utils/google-places/loadGoogleMapsScript.test.ts +68 -8
  803. package/src/utils/google-places/loadGoogleMapsScript.ts +140 -118
  804. package/src/utils/index.ts +52 -11
  805. package/src/utils/index.unit.test.ts +251 -0
  806. package/src/utils/lazyLoad.unit.test.tsx +319 -0
  807. package/src/utils/location/location.test.ts +19 -116
  808. package/src/utils/logger.unit.test.ts +398 -0
  809. package/src/utils/organisationContext.unit.test.ts +180 -0
  810. package/src/utils/performance/bundleAnalysis.test.ts +148 -0
  811. package/src/utils/performance/bundleAnalysis.ts +16 -22
  812. package/src/utils/performance/performanceBenchmark.test.ts +251 -0
  813. package/src/utils/performance/performanceBenchmark.ts +12 -4
  814. package/src/utils/performance/performanceBudgets.test.ts +241 -0
  815. package/src/utils/performance/performanceBudgets.ts +9 -6
  816. package/src/utils/performanceBenchmark.test.ts +174 -0
  817. package/src/utils/performanceBudgets.unit.test.ts +288 -0
  818. package/src/utils/permissionTypes.unit.test.ts +250 -0
  819. package/src/utils/permissionUtils.unit.test.ts +362 -0
  820. package/src/utils/permissions/permissionTypes.test.ts +149 -0
  821. package/src/utils/permissions/permissionUtils.test.ts +20 -42
  822. package/src/utils/persistence/keyDerivation.test.ts +306 -0
  823. package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
  824. package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
  825. package/src/utils/request-deduplication.test.ts +349 -0
  826. package/src/utils/request-deduplication.ts +6 -4
  827. package/src/utils/sanitization.unit.test.ts +346 -0
  828. package/src/utils/schemaUtils.unit.test.ts +441 -0
  829. package/src/utils/secureDataAccess.unit.test.ts +334 -0
  830. package/src/utils/secureErrors.unit.test.ts +390 -0
  831. package/src/utils/secureStorage.unit.test.ts +289 -0
  832. package/src/utils/security/auth-utils.ts +38 -27
  833. package/src/utils/security/secureDataAccess.test.ts +22 -191
  834. package/src/utils/security/secureDataAccess.ts +241 -281
  835. package/src/utils/security/secureErrors.test.ts +163 -0
  836. package/src/utils/security/secureStorage.test.ts +156 -0
  837. package/src/utils/security/secureStorage.ts +1 -1
  838. package/src/utils/security/security.test.ts +212 -0
  839. package/src/utils/security/security.ts +15 -18
  840. package/src/utils/security/securityMonitor.test.ts +90 -0
  841. package/src/utils/security/securityMonitor.ts +1 -1
  842. package/src/utils/security.unit.test.ts +155 -0
  843. package/src/utils/securityMonitor.unit.test.ts +276 -0
  844. package/src/utils/sessionTracking.unit.test.ts +218 -0
  845. package/src/utils/storage/config.unit.test.ts +239 -0
  846. package/src/utils/storage/helpers.test.ts +769 -456
  847. package/src/utils/storage/helpers.ts +174 -253
  848. package/src/utils/storage/index.unit.test.ts +68 -0
  849. package/src/utils/storage/storageUtils.ts +32 -0
  850. package/src/utils/storage/types.ts +9 -2
  851. package/src/utils/supabase/createBaseClient.test.ts +201 -0
  852. package/src/utils/supabase/createBaseClient.ts +2 -1
  853. package/src/utils/timezone/timezone.test.ts +26 -44
  854. package/src/utils/timezone.test.ts +345 -0
  855. package/src/utils/validation/common.test.ts +115 -0
  856. package/src/utils/validation/csrf.test.ts +198 -0
  857. package/src/utils/validation/csrf.ts +42 -41
  858. package/src/utils/validation/htmlSanitization.ts +27 -31
  859. package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
  860. package/src/utils/validation/passwordSchema.test.ts +164 -0
  861. package/src/utils/validation/schema.test.ts +127 -0
  862. package/src/utils/validation/schema.ts +6 -3
  863. package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
  864. package/src/utils/validation/sqlInjectionProtection.ts +2 -2
  865. package/src/utils/validation/user.test.ts +173 -0
  866. package/src/utils/validation/validation.test.ts +197 -0
  867. package/src/utils/validation/validationUtils.test.ts +294 -0
  868. package/src/utils/validation.unit.test.ts +307 -0
  869. package/src/utils/validationUtils.unit.test.ts +558 -0
  870. package/src/vite-env.d.ts +6 -0
  871. package/dist/AuthService-DmfO5rGS.d.ts +0 -524
  872. package/dist/DataTable-DRUIgtUH.d.ts +0 -166
  873. package/dist/DataTable-SOAFXIWY.js +0 -15
  874. package/dist/PublicPageProvider-CIGSujI2.d.ts +0 -4147
  875. package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
  876. package/dist/UnifiedAuthProvider-CKvHP1MK.d.ts +0 -139
  877. package/dist/api-7P7DI652.js +0 -4
  878. package/dist/audit-MYQXYZFU.js +0 -3
  879. package/dist/auth-BZOJqrdd.d.ts +0 -49
  880. package/dist/chunk-4DDCYDQ3.js +0 -544
  881. package/dist/chunk-5HNSDQWH.js +0 -5046
  882. package/dist/chunk-5W2A3DRC.js +0 -164
  883. package/dist/chunk-6GLLNA6U.js +0 -31
  884. package/dist/chunk-7ILTDCL2.js +0 -80
  885. package/dist/chunk-A3W6LW53.js +0 -70
  886. package/dist/chunk-AHU7G2R5.js +0 -423
  887. package/dist/chunk-C7ZQ5O4C.js +0 -481
  888. package/dist/chunk-EF2UGZWY.js +0 -611
  889. package/dist/chunk-FEJLJNWA.js +0 -181
  890. package/dist/chunk-FYHN4DD5.js +0 -415
  891. package/dist/chunk-GS5672WG.js +0 -2003
  892. package/dist/chunk-HF6O3O37.js +0 -187
  893. package/dist/chunk-J2U36LHD.js +0 -8517
  894. package/dist/chunk-LX6U42O3.js +0 -2177
  895. package/dist/chunk-MPBLMWVR.js +0 -2161
  896. package/dist/chunk-OJ4SKRSV.js +0 -105
  897. package/dist/chunk-S6ZQKDY6.js +0 -62
  898. package/dist/chunk-S7DKJPLT.js +0 -699
  899. package/dist/chunk-T5CVK4R3.js +0 -2816
  900. package/dist/chunk-TTRFSOKR.js +0 -121
  901. package/dist/chunk-Z2FNRKF3.js +0 -994
  902. package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
  903. package/dist/event-CW5YB_2p.d.ts +0 -239
  904. package/dist/file-reference-BavO2eQj.d.ts +0 -148
  905. package/dist/functions-lBy5L2ry.d.ts +0 -208
  906. package/dist/timezone-0AyangqX.d.ts +0 -697
  907. package/dist/types-BeoeWV5I.d.ts +0 -110
  908. package/dist/types-DXstZpNI.d.ts +0 -614
  909. package/dist/types-t9H8qKRw.d.ts +0 -55
  910. package/dist/usePublicRouteParams-DQLrDqDb.d.ts +0 -876
  911. package/dist/useToast-AyaT-x7p.d.ts +0 -68
  912. package/dist/validation-643vUDZW.d.ts +0 -177
  913. package/scripts/build-docs-incremental.js +0 -179
  914. package/scripts/eslint-audit.cjs +0 -123
  915. package/scripts/generate-docs.js +0 -157
  916. package/scripts/install-cursor-rules.cjs +0 -255
  917. package/scripts/install-eslint-config.cjs +0 -349
  918. package/scripts/setup-build-cache.js +0 -73
  919. package/scripts/validate-pre-publish.js +0 -145
  920. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
  921. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
  922. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
  923. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
  924. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -448
  925. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
  926. package/src/__tests__/hooks/usePermissions.test.ts +0 -268
  927. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  928. package/src/__tests__/public-recipe-view.test.ts +0 -228
  929. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -220
  930. package/src/__tests__/rls-policies.test.ts +0 -471
  931. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
  932. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
  933. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
  934. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
  935. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
  936. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -483
  937. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  938. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
  939. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -1474
  940. package/src/components/DataTable/__tests__/README.md +0 -145
  941. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
  942. package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
  943. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
  944. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -730
  945. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -325
  946. package/src/components/DataTable/__tests__/styles.test.ts +0 -382
  947. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
  948. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -380
  949. package/src/components/DataTable/__tests__/test-utils.ts +0 -94
  950. package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
  951. package/src/components/DataTable/components/ActionButtons.tsx +0 -190
  952. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
  953. package/src/components/DataTable/components/ColumnFilter.tsx +0 -118
  954. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
  955. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
  956. package/src/components/DataTable/components/DataTableLayout.tsx +0 -573
  957. package/src/components/DataTable/components/DataTableModals.tsx +0 -245
  958. package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
  959. package/src/components/DataTable/components/EditFields.tsx +0 -327
  960. package/src/components/DataTable/components/EditableRow.tsx +0 -462
  961. package/src/components/DataTable/components/EmptyState.tsx +0 -79
  962. package/src/components/DataTable/components/FilterRow.tsx +0 -141
  963. package/src/components/DataTable/components/LoadingState.tsx +0 -17
  964. package/src/components/DataTable/components/PaginationControls.tsx +0 -289
  965. package/src/components/DataTable/components/RowComponent.tsx +0 -403
  966. package/src/components/DataTable/components/SortIndicator.tsx +0 -50
  967. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -355
  968. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -657
  969. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -913
  970. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -572
  971. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -612
  972. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -708
  973. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -479
  974. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -475
  975. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -157
  976. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -1061
  977. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -437
  978. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -474
  979. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -617
  980. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -1093
  981. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -139
  982. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -519
  983. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -1004
  984. package/src/components/DataTable/components/cellValueUtils.ts +0 -40
  985. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
  986. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
  987. package/src/components/DataTable/components/index.ts +0 -16
  988. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -342
  989. package/src/components/DataTable/core/ActionManager.ts +0 -235
  990. package/src/components/DataTable/core/ColumnManager.ts +0 -205
  991. package/src/components/DataTable/core/DataManager.ts +0 -188
  992. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  993. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  994. package/src/components/DataTable/core/StateManager.ts +0 -312
  995. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -123
  996. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -305
  997. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -84
  998. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -115
  999. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -100
  1000. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -120
  1001. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -104
  1002. package/src/components/DataTable/core/index.ts +0 -1
  1003. package/src/components/DataTable/core/interfaces.ts +0 -338
  1004. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -521
  1005. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -167
  1006. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -124
  1007. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -117
  1008. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -102
  1009. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -596
  1010. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -53
  1011. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -214
  1012. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -448
  1013. package/src/components/DataTable/hooks/index.ts +0 -13
  1014. package/src/components/DataTable/types.ts +0 -761
  1015. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -612
  1016. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
  1017. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -266
  1018. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
  1019. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
  1020. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -247
  1021. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -570
  1022. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
  1023. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -251
  1024. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -207
  1025. package/src/components/DataTable/utils/index.ts +0 -10
  1026. package/src/components/PublicLayout/index.ts +0 -32
  1027. package/src/components/Select/hooks/useSelectEvents.ts +0 -87
  1028. package/src/components/Select/hooks/useSelectSearch.ts +0 -91
  1029. package/src/components/Select/hooks/useSelectState.ts +0 -104
  1030. package/src/components/Select/utils/text.ts +0 -26
  1031. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -615
  1032. package/src/hooks/__tests__/hooks.integration.test.tsx +0 -607
  1033. package/src/hooks/__tests__/index.unit.test.ts +0 -220
  1034. package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -111
  1035. package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -347
  1036. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -144
  1037. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -776
  1038. package/src/hooks/__tests__/useDataTableState.test.ts +0 -76
  1039. package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
  1040. package/src/hooks/__tests__/useEvents.unit.test.ts +0 -252
  1041. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1112
  1042. package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -916
  1043. package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -129
  1044. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -230
  1045. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -828
  1046. package/src/hooks/__tests__/useFormDialog.test.ts +0 -478
  1047. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
  1048. package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
  1049. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -910
  1050. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -294
  1051. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
  1052. package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
  1053. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
  1054. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  1055. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  1056. package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -88
  1057. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -785
  1058. package/src/hooks/__tests__/usePublicEvent.test.ts +0 -678
  1059. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -630
  1060. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -951
  1061. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -443
  1062. package/src/hooks/__tests__/useQueryCache.test.ts +0 -144
  1063. package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
  1064. package/src/hooks/__tests__/useSessionDraft.test.ts +0 -163
  1065. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
  1066. package/src/hooks/__tests__/useStorage.unit.test.ts +0 -751
  1067. package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
  1068. package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
  1069. package/src/hooks/public/index.ts +0 -36
  1070. package/src/hooks/public/usePublicFileDisplay.ts +0 -504
  1071. package/src/hooks/useFileDisplay.ts +0 -715
  1072. package/src/providers/OrganisationProvider.tsx +0 -92
  1073. package/src/providers/__tests__/AuthProvider.test.tsx +0 -287
  1074. package/src/providers/__tests__/EventProvider.test.tsx +0 -551
  1075. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  1076. package/src/providers/__tests__/InactivityProvider.test.tsx +0 -572
  1077. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -617
  1078. package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -424
  1079. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -596
  1080. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -263
  1081. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -294
  1082. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -434
  1083. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -313
  1084. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -486
  1085. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -399
  1086. package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -813
  1087. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
  1088. package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
  1089. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -392
  1090. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -258
  1091. package/src/rbac/__tests__/rbac-functions.test.ts +0 -647
  1092. package/src/rbac/__tests__/rbac-integration.test.ts +0 -524
  1093. package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
  1094. package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -282
  1095. package/src/rbac/audit-enhanced.ts +0 -384
  1096. package/src/rbac/compliance/database-validator.ts +0 -165
  1097. package/src/rbac/compliance/index.ts +0 -48
  1098. package/src/rbac/compliance/pattern-detector.ts +0 -553
  1099. package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
  1100. package/src/rbac/compliance/runtime-compliance.ts +0 -99
  1101. package/src/rbac/compliance/setup-validator.ts +0 -131
  1102. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -975
  1103. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -248
  1104. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -242
  1105. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1107
  1106. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -184
  1107. package/src/rbac/components/index.ts +0 -26
  1108. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -432
  1109. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -579
  1110. package/src/rbac/hooks/index.ts +0 -34
  1111. package/src/rbac/hooks/permissions/index.ts +0 -4
  1112. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  1113. package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -128
  1114. package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -53
  1115. package/src/rbac/utils/__tests__/eventContext.test.ts +0 -433
  1116. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
  1117. package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -39
  1118. package/src/services/__tests__/AuthService.test.ts +0 -1332
  1119. package/src/services/__tests__/BaseService.test.ts +0 -314
  1120. package/src/services/__tests__/EventService.eventColours.test.ts +0 -76
  1121. package/src/services/__tests__/EventService.test.ts +0 -1025
  1122. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -411
  1123. package/src/services/__tests__/InactivityService.test.ts +0 -654
  1124. package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
  1125. package/src/services/__tests__/OrganisationService.test.ts +0 -1176
  1126. package/src/theming/__tests__/parseEventColours.test.ts +0 -321
  1127. package/src/theming/__tests__/runtime.test.ts +0 -569
  1128. package/src/types/__tests__/file-reference.test.ts +0 -447
  1129. package/src/types/__tests__/guards.test.ts +0 -246
  1130. package/src/types/__tests__/organisation.roles.test.ts +0 -55
  1131. package/src/types/__tests__/organisation.test.ts +0 -1133
  1132. package/src/types/__tests__/theme.test.ts +0 -830
  1133. package/src/types/__tests__/type-validation.test.ts +0 -526
  1134. package/src/types/__tests__/validation.test.ts +0 -731
  1135. package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
  1136. package/src/utils/__tests__/audit.unit.test.ts +0 -69
  1137. package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
  1138. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -339
  1139. package/src/utils/__tests__/cn.unit.test.ts +0 -34
  1140. package/src/utils/__tests__/debugLogger.test.ts +0 -417
  1141. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
  1142. package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -318
  1143. package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
  1144. package/src/utils/__tests__/formatting.unit.test.ts +0 -99
  1145. package/src/utils/__tests__/index.unit.test.ts +0 -251
  1146. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -321
  1147. package/src/utils/__tests__/logger.unit.test.ts +0 -398
  1148. package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
  1149. package/src/utils/__tests__/performanceBenchmark.test.ts +0 -175
  1150. package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -253
  1151. package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
  1152. package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
  1153. package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
  1154. package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
  1155. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -335
  1156. package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
  1157. package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
  1158. package/src/utils/__tests__/security.unit.test.ts +0 -149
  1159. package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
  1160. package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
  1161. package/src/utils/__tests__/timezone.test.ts +0 -345
  1162. package/src/utils/__tests__/validation.unit.test.ts +0 -308
  1163. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
  1164. package/src/utils/app/appNameResolver.simple.test.ts +0 -212
  1165. package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -875
  1166. package/src/utils/google-places/index.ts +0 -26
  1167. package/src/utils/location/index.ts +0 -16
  1168. package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -135
  1169. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -123
  1170. package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
  1171. package/src/utils/storage/__tests__/index.unit.test.ts +0 -16
  1172. package/src/utils/storage/index.ts +0 -67
  1173. package/src/utils/timezone/index.ts +0 -17
  1174. package/src/utils/validation/__tests__/csrf.test.ts +0 -105
  1175. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -598
  1176. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -92
  1177. package/src/utils/validation/__tests__/validationUtils.test.ts +0 -72
  1178. package/src/utils/validation/index.ts +0 -73
  1179. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  1180. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  1181. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  1182. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -1,2003 +0,0 @@
1
- import { useAppConfig, useOrganisationSecurity } from './chunk-EF2UGZWY.js';
2
- import { useEventService, useUnifiedAuth, useOrganisations } from './chunk-T5CVK4R3.js';
3
- import { OrganisationContextRequiredError, getRBACLogger, resolveAppContext, getPageScopeType, ContextValidator, getPermissionMap, getRoleContext, getAccessLevel, isPermittedCached, isPermitted, isSuperAdmin } from './chunk-LX6U42O3.js';
4
- import { getCurrentAppName } from './chunk-OJ4SKRSV.js';
5
- import { cn } from './chunk-7ILTDCL2.js';
6
- import { createLogger, logger } from './chunk-TTRFSOKR.js';
7
- import * as React2 from 'react';
8
- import { useRef, useMemo, useState, useCallback, useEffect } from 'react';
9
- import * as TooltipPrimitive from '@radix-ui/react-tooltip';
10
- import { jsx, jsxs } from 'react/jsx-runtime';
11
- import { Slot } from '@radix-ui/react-slot';
12
- import { createClient } from '@supabase/supabase-js';
13
-
14
- function useEvents() {
15
- const eventService = useEventService();
16
- const rawEvents = eventService.getEvents();
17
- const selectedEvent = eventService.getSelectedEvent();
18
- const isLoading = eventService.isLoading();
19
- const error = eventService.getError();
20
- const prevEventsRef = useRef([]);
21
- const prevEventsIdsRef = useRef("");
22
- const currentEventsIds = rawEvents.map((e) => e.event_id || e.id).join(",");
23
- const eventsChanged = currentEventsIds !== prevEventsIdsRef.current;
24
- if (eventsChanged) {
25
- prevEventsRef.current = rawEvents;
26
- prevEventsIdsRef.current = currentEventsIds;
27
- }
28
- const events = useMemo(() => {
29
- return prevEventsRef.current;
30
- }, [currentEventsIds]);
31
- const setSelectedEventCallback = useMemo(
32
- () => (event) => eventService.setSelectedEvent(event),
33
- [eventService]
34
- );
35
- const refreshEventsCallback = useMemo(
36
- () => () => eventService.refreshEvents(),
37
- [eventService]
38
- );
39
- const clearEventSelectionCallback = useMemo(
40
- () => () => eventService.clearEventSelection(),
41
- [eventService]
42
- );
43
- return useMemo(() => ({
44
- events,
45
- selectedEvent,
46
- isLoading,
47
- error,
48
- setSelectedEvent: setSelectedEventCallback,
49
- refreshEvents: refreshEventsCallback,
50
- clearEventSelection: clearEventSelectionCallback
51
- }), [events, selectedEvent?.event_id, isLoading, error?.message, setSelectedEventCallback, refreshEventsCallback, clearEventSelectionCallback]);
52
- }
53
- var TooltipProvider = TooltipPrimitive.Provider;
54
- var TooltipRoot = TooltipPrimitive.Root;
55
- var TooltipTrigger = TooltipPrimitive.Trigger;
56
- var TooltipContent = React2.forwardRef(({ className, sideOffset = 4, ...props }, ref) => /* @__PURE__ */ jsx(
57
- TooltipPrimitive.Content,
58
- {
59
- ref,
60
- sideOffset,
61
- className: cn(
62
- "z-50 overflow-hidden rounded-md border bg-main-500 px-3 py-1.5 text-sm text-main-50 shadow-md animate-in fade-in-0 zoom-in-95 data-[state=closed]:animate-out data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-95 data-[side=bottom]:slide-in-from-top-2 data-[side=left]:slide-in-from-right-2 data-[side=right]:slide-in-from-left-2 data-[side=top]:slide-in-from-bottom-2",
63
- className
64
- ),
65
- ...props
66
- }
67
- ));
68
- TooltipContent.displayName = TooltipPrimitive.Content.displayName;
69
- var Tooltip = React2.forwardRef(({ children, content, delayDuration = 200 }, ref) => /* @__PURE__ */ jsx(TooltipProvider, { children: /* @__PURE__ */ jsxs(TooltipRoot, { delayDuration, children: [
70
- /* @__PURE__ */ jsx(TooltipTrigger, { ref, asChild: true, children: /* @__PURE__ */ jsx("span", { children }) }),
71
- /* @__PURE__ */ jsx(TooltipContent, { children: content })
72
- ] }) }));
73
- Tooltip.displayName = "Tooltip";
74
- function getButtonClasses(variant = "default", size = "default") {
75
- const baseClasses = "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50";
76
- const variantClasses = {
77
- default: "bg-main-600 text-main-50 shadow hover:bg-acc-400",
78
- destructive: "bg-acc-600 text-acc-50 shadow-sm hover:bg-acc-400",
79
- outline: "border border-main-300 bg-background shadow-sm hover:bg-acc-400",
80
- secondary: "bg-sec-100 text-sec-900 shadow-sm hover:bg-acc-400",
81
- ghost: "hover:bg-acc-400",
82
- link: "text-main-700 underline-offset-4 hover:underline hover:drop-shadow-lg hover:drop-shadow-acc-400"
83
- };
84
- const sizeClasses = {
85
- default: "h-9 px-4 py-2",
86
- sm: "h-8 rounded-md px-3 text-xs",
87
- lg: "h-10 rounded-md px-8",
88
- icon: "size-8"
89
- };
90
- return `${baseClasses} ${variantClasses[variant]} ${sizeClasses[size]}`;
91
- }
92
- var Button = React2.forwardRef(
93
- ({ className, variant, size, asChild = false, type = "button", disabled, ...props }, ref) => {
94
- const Comp = asChild ? Slot : "button";
95
- return /* @__PURE__ */ jsx(
96
- Comp,
97
- {
98
- className: cn(getButtonClasses(variant, size), className),
99
- ref,
100
- type: !asChild ? type : void 0,
101
- disabled,
102
- "aria-disabled": disabled ? "true" : void 0,
103
- ...props
104
- }
105
- );
106
- }
107
- );
108
- Button.displayName = "Button";
109
- function ButtonGroup({
110
- children,
111
- orientation = "horizontal",
112
- variant,
113
- size,
114
- className,
115
- spacing = "sm"
116
- }) {
117
- const spacingClasses = {
118
- none: "",
119
- sm: orientation === "horizontal" ? "space-x-1" : "space-y-1",
120
- md: orientation === "horizontal" ? "space-x-2" : "space-y-2",
121
- lg: orientation === "horizontal" ? "space-x-4" : "space-y-4"
122
- };
123
- return /* @__PURE__ */ jsx(
124
- "fieldset",
125
- {
126
- className: cn(
127
- "flex",
128
- orientation === "horizontal" ? "flex-row items-center" : "flex-col",
129
- spacingClasses[spacing],
130
- className
131
- ),
132
- role: "group",
133
- children: React2.Children.map(children, (child) => {
134
- if (React2.isValidElement(child) && child.type) {
135
- const componentType = child.type;
136
- if (componentType.displayName === "Button") {
137
- const childProps = child.props;
138
- return React2.cloneElement(child, {
139
- variant: childProps.variant || variant,
140
- size: childProps.size || size,
141
- ...childProps
142
- });
143
- }
144
- }
145
- return child;
146
- })
147
- }
148
- );
149
- }
150
- var IconButton = React2.forwardRef(
151
- ({ icon, className, size = "icon", "aria-label": ariaLabel, tooltip, ...props }, ref) => {
152
- const button = /* @__PURE__ */ jsx(
153
- Button,
154
- {
155
- ref,
156
- size,
157
- className: cn("shrink-0", className),
158
- "aria-label": ariaLabel,
159
- ...props,
160
- children: icon
161
- }
162
- );
163
- if (tooltip) {
164
- return /* @__PURE__ */ jsx(Tooltip, { content: tooltip, children: button });
165
- }
166
- return button;
167
- }
168
- );
169
- IconButton.displayName = "IconButton";
170
-
171
- // src/rbac/utils/clientSecurity.ts
172
- var SECURE_CLIENT_SYMBOL = Symbol("pace-core-secure-client");
173
- function isSecureClient(client) {
174
- if (!client) return false;
175
- return client[SECURE_CLIENT_SYMBOL] === true;
176
- }
177
- function warnIfInsecureClient(client, context) {
178
- if (typeof process !== "undefined" && true) {
179
- return;
180
- }
181
- if (!client) return;
182
- if (!isSecureClient(client)) {
183
- const contextMsg = context ? ` in ${context}` : "";
184
- console.warn(
185
- `[pace-core Security Warning] Non-secure Supabase client detected${contextMsg}.
186
- You are using a Supabase client created with createClient() instead of useSecureSupabase().
187
- This bypasses organisation context enforcement and RLS policies, which can lead to:
188
- - Cross-organisation data access
189
- - Security vulnerabilities
190
- - Data leakage between organisations
191
-
192
- Fix: Replace with:
193
- import { useSecureSupabase } from '@jmruthers/pace-core/rbac';
194
- const supabase = useSecureSupabase();
195
-
196
- See: https://github.com/jmruthers/pace-core/blob/main/packages/core/docs/rbac/getting-started.md`
197
- );
198
- }
199
- }
200
- function markClientAsSecure(client) {
201
- client[SECURE_CLIENT_SYMBOL] = true;
202
- }
203
- var _SecureSupabaseClient = class _SecureSupabaseClient {
204
- constructor(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2 = false, existingClient) {
205
- this.edgeFunctionClient = null;
206
- this.usesExistingClient = false;
207
- this.supabaseUrl = supabaseUrl;
208
- this.supabaseKey = supabaseKey;
209
- this.organisationId = organisationId;
210
- this.eventId = eventId;
211
- this.appId = appId;
212
- this.isSuperAdmin = isSuperAdmin2;
213
- if (existingClient) {
214
- this.supabase = existingClient;
215
- this.usesExistingClient = true;
216
- } else {
217
- this.supabase = createClient(supabaseUrl, supabaseKey, {
218
- global: {
219
- headers: {
220
- "x-organisation-id": organisationId || "",
221
- "x-event-id": eventId || "",
222
- "x-app-id": appId || ""
223
- }
224
- }
225
- });
226
- }
227
- this.setupContextInjection();
228
- this.setupEdgeFunctionHandling();
229
- markClientAsSecure(this.supabase);
230
- }
231
- /**
232
- * Setup context injection for all database operations
233
- */
234
- setupContextInjection() {
235
- const originalFrom = this.supabase.from.bind(this.supabase);
236
- this.supabase.from = (table) => {
237
- this.validateContextForTable(table);
238
- const query = originalFrom(table);
239
- query._tableName = table;
240
- return this.injectContext(query, table);
241
- };
242
- const originalRpc = this.supabase.rpc.bind(this.supabase);
243
- this.supabase.rpc = (fn, args, options) => {
244
- this.validateContextForRpc(fn);
245
- const acceptedParams = this.getRpcAcceptedParams(fn);
246
- const safeArgs = args ?? {};
247
- const contextArgs = { ...safeArgs };
248
- if (acceptedParams.has("p_organisation_id") && this.organisationId && safeArgs.p_organisation_id === void 0) {
249
- contextArgs.p_organisation_id = this.organisationId;
250
- }
251
- if (acceptedParams.has("p_event_id") && this.eventId && safeArgs.p_event_id === void 0) {
252
- contextArgs.p_event_id = this.eventId;
253
- }
254
- if (acceptedParams.has("p_app_id") && this.appId && safeArgs.p_app_id === void 0) {
255
- contextArgs.p_app_id = this.appId;
256
- }
257
- return originalRpc(fn, contextArgs, options);
258
- };
259
- }
260
- /**
261
- * Setup Edge Function handling to bypass custom headers
262
- * Edge Functions may not have CORS configured to accept custom headers,
263
- * so we create a separate client without custom headers for Edge Function calls
264
- *
265
- * NOTE: We store the edge function client but don't override functions here.
266
- * Instead, we provide a method to get the edge function client for direct use.
267
- * This avoids interfering with the main client's operations.
268
- */
269
- setupEdgeFunctionHandling() {
270
- if (this.usesExistingClient) {
271
- this.edgeFunctionClient = null;
272
- return;
273
- }
274
- this.edgeFunctionClient = createClient(this.supabaseUrl, this.supabaseKey);
275
- }
276
- /**
277
- * Get a client for Edge Function calls without custom headers
278
- * Edge Functions may not have CORS configured to accept custom headers
279
- * @returns Supabase client without custom headers for Edge Function calls
280
- */
281
- getEdgeFunctionClient() {
282
- return this.edgeFunctionClient || this.supabase;
283
- }
284
- /**
285
- * Inject organisation context into a query
286
- */
287
- injectContext(query, tableName) {
288
- const originalSelect = query.select.bind(query);
289
- const originalInsert = query.insert.bind(query);
290
- const originalUpdate = query.update.bind(query);
291
- const originalDelete = query.delete.bind(query);
292
- query.select = (columns) => {
293
- const result = originalSelect(columns);
294
- result._tableName = tableName;
295
- return this.addOrganisationFilter(result, tableName);
296
- };
297
- query.insert = (values) => {
298
- const tablesWithoutOrganisationId = [
299
- "core_organisations",
300
- // Organisation table itself - uses 'id' as primary key
301
- "rbac_apps",
302
- // App configuration table - no organisation scope
303
- "rbac_app_pages",
304
- // Page configuration table - scoped by app_id, not organisation_id
305
- "rbac_global_roles"
306
- // Global roles - no organisation scope
307
- ];
308
- if (tablesWithoutOrganisationId.includes(tableName)) {
309
- return originalInsert(values);
310
- }
311
- if (tableName === "rbac_user_profiles") {
312
- if (this.isSuperAdmin) {
313
- return originalInsert(values);
314
- }
315
- if (!this.organisationId) {
316
- throw new OrganisationContextRequiredError();
317
- }
318
- const contextValues2 = Array.isArray(values) ? values.map((v) => ({ ...v, organisation_id: this.organisationId })) : { ...values, organisation_id: this.organisationId };
319
- return originalInsert(contextValues2);
320
- }
321
- if (this.isSuperAdmin && !this.organisationId) {
322
- return originalInsert(values);
323
- }
324
- if (!this.organisationId) {
325
- throw new OrganisationContextRequiredError();
326
- }
327
- const contextValues = Array.isArray(values) ? values.map((v) => ({ ...v, organisation_id: this.organisationId })) : { ...values, organisation_id: this.organisationId };
328
- return originalInsert(contextValues);
329
- };
330
- query.update = (values) => {
331
- const result = originalUpdate(values);
332
- return this.addOrganisationFilter(result, tableName);
333
- };
334
- query.delete = () => {
335
- const result = originalDelete();
336
- return this.addOrganisationFilter(result, tableName);
337
- };
338
- return query;
339
- }
340
- /**
341
- * Add organisation filter to a query
342
- *
343
- * Defense in depth strategy:
344
- * - RLS policies are the primary security layer (cannot be bypassed)
345
- * - Application-level filtering adds an additional layer of protection
346
- *
347
- * For rbac_user_profiles:
348
- * - Super admins: No org filter (see all users) - RLS will allow access
349
- * - Non-super-admins: Apply org filter as defense in depth - RLS will also filter
350
- *
351
- * For system-wide tables (like core_organisations):
352
- * - Super admins: No org filter (see all records) - RLS will allow access
353
- * - Non-super-admins: Apply org filter as defense in depth - RLS will also filter
354
- *
355
- * For other tables:
356
- * - Always apply org filter unless super admin bypasses it
357
- */
358
- addOrganisationFilter(query, tableName) {
359
- const tablesWithoutOrganisationId = [
360
- "core_organisations",
361
- // Organisation table itself - uses 'id' as primary key
362
- "rbac_apps",
363
- // App configuration table - no organisation scope
364
- "rbac_app_pages",
365
- // Page configuration table - scoped by app_id, not organisation_id
366
- "rbac_global_roles",
367
- // Global roles - no organisation scope
368
- // Person-scoped tables (organisation_id was removed in person-scoped profiles migration)
369
- "core_person",
370
- // Person records - person-scoped, no organisation_id
371
- "core_member",
372
- // Member profiles - person-scoped, no organisation_id
373
- "core_contact",
374
- // Contact profiles - person-scoped, no organisation_id
375
- "core_consent",
376
- // Consent records - person-scoped, no organisation_id
377
- "core_identification",
378
- // Identification records - person-scoped, no organisation_id
379
- "core_qualification",
380
- // Qualification records - person-scoped, no organisation_id
381
- "medi_profile",
382
- // Medical profiles - person-scoped, no organisation_id
383
- "medi_condition",
384
- // Medical conditions - person-scoped via medi_profile, no organisation_id
385
- "medi_diet",
386
- // Medical diets - person-scoped via medi_profile, no organisation_id
387
- "medi_action_plan",
388
- // Medical action plans - person-scoped via medi_profile, no organisation_id
389
- "medi_profile_versions"
390
- // Medical profile versions - person-scoped via medi_profile, no organisation_id
391
- ];
392
- if (tablesWithoutOrganisationId.includes(tableName)) {
393
- return query;
394
- }
395
- if (!this.organisationId) {
396
- return query;
397
- }
398
- const systemWideTablesForSuperAdmins = [
399
- "core_organisations"
400
- // Super-admins need to see all organisations
401
- ];
402
- if (systemWideTablesForSuperAdmins.includes(tableName) && this.isSuperAdmin) {
403
- return query;
404
- }
405
- if (tableName === "rbac_user_profiles") {
406
- if (this.isSuperAdmin) {
407
- return query;
408
- }
409
- return query.or(`organisation_id.eq.${this.organisationId},organisation_id.is.null`);
410
- }
411
- if (this.isSuperAdmin) {
412
- return query.eq("organisation_id", this.organisationId);
413
- }
414
- return query.eq("organisation_id", this.organisationId);
415
- }
416
- /**
417
- * Validate that required context is present
418
- * Super-admins can operate without organisation context
419
- */
420
- validateContext() {
421
- if (this.isSuperAdmin) {
422
- return;
423
- }
424
- if (!this.organisationId) {
425
- throw new OrganisationContextRequiredError();
426
- }
427
- }
428
- /**
429
- * Determine whether a table requires organisation context.
430
- * Tables without an organisation_id column (or global configuration tables) are safe without org context.
431
- */
432
- tableRequiresOrganisationContext(tableName) {
433
- const tablesWithoutOrganisationId = /* @__PURE__ */ new Set([
434
- "core_organisations",
435
- "rbac_apps",
436
- "rbac_app_pages",
437
- "rbac_global_roles",
438
- "core_person",
439
- "core_member",
440
- "core_contact",
441
- "core_consent",
442
- "core_identification",
443
- "core_qualification",
444
- "medi_profile",
445
- "medi_condition",
446
- "medi_diet",
447
- "medi_action_plan",
448
- "medi_profile_versions"
449
- ]);
450
- return !tablesWithoutOrganisationId.has(tableName);
451
- }
452
- /**
453
- * Validate context for a specific table operation.
454
- */
455
- validateContextForTable(tableName) {
456
- if (this.isSuperAdmin) return;
457
- if (!this.organisationId && this.tableRequiresOrganisationContext(tableName)) {
458
- throw new OrganisationContextRequiredError();
459
- }
460
- }
461
- /**
462
- * Validate context for a specific RPC call.
463
- */
464
- validateContextForRpc(fn) {
465
- if (this.isSuperAdmin) return;
466
- if (_SecureSupabaseClient.GLOBAL_RPC_ALLOWLIST.has(fn)) return;
467
- this.validateContext();
468
- }
469
- /**
470
- * Get the current organisation ID
471
- */
472
- getOrganisationId() {
473
- return this.organisationId;
474
- }
475
- /**
476
- * Get the current event ID
477
- */
478
- getEventId() {
479
- return this.eventId;
480
- }
481
- /**
482
- * Get the current app ID
483
- */
484
- getAppId() {
485
- return this.appId;
486
- }
487
- /**
488
- * Create a new client with updated context
489
- */
490
- withContext(updates) {
491
- return new _SecureSupabaseClient(
492
- this.supabaseUrl,
493
- this.supabaseKey,
494
- updates.organisationId !== void 0 ? updates.organisationId : this.organisationId,
495
- updates.eventId !== void 0 ? updates.eventId : this.eventId,
496
- updates.appId !== void 0 ? updates.appId : this.appId,
497
- updates.isSuperAdmin !== void 0 ? updates.isSuperAdmin : this.isSuperAdmin
498
- );
499
- }
500
- /**
501
- * Get the underlying Supabase client (for internal use only)
502
- * @internal
503
- */
504
- getClient() {
505
- const proxiedClient = new Proxy(this.supabase, {
506
- get: (target, prop) => {
507
- if (prop === "functions" && this.edgeFunctionClient) {
508
- return this.edgeFunctionClient.functions;
509
- }
510
- return target[prop];
511
- }
512
- });
513
- markClientAsSecure(proxiedClient);
514
- return proxiedClient;
515
- }
516
- /**
517
- * Get the set of parameter names that an RPC function accepts.
518
- * Uses a static whitelist of RPCs that we know accept context parameters.
519
- *
520
- * This is an opt-in approach: by default, we don't inject context unless
521
- * the function is explicitly whitelisted. This prevents PGRST202 errors from
522
- * injecting unexpected parameters.
523
- *
524
- * @param fn - The RPC function name
525
- * @returns Set of parameter names the function accepts
526
- */
527
- getRpcAcceptedParams(fn) {
528
- if (_SecureSupabaseClient.rpcSignatureCache.has(fn)) {
529
- return _SecureSupabaseClient.rpcSignatureCache.get(fn);
530
- }
531
- const rpcContextWhitelist = {
532
- // RPCs that accept all three context parameters
533
- "data_rbac_roles_list": /* @__PURE__ */ new Set(["p_organisation_id", "p_event_id", "p_app_id"]),
534
- // RPCs that accept only p_organisation_id (not p_app_id or p_event_id)
535
- "data_file_reference_by_category_list": /* @__PURE__ */ new Set(["p_organisation_id"])
536
- // Add more RPCs here as we discover them
537
- // Format: 'function_name': new Set(['p_organisation_id', 'p_event_id', 'p_app_id']),
538
- };
539
- const acceptedParams = rpcContextWhitelist[fn] || /* @__PURE__ */ new Set();
540
- _SecureSupabaseClient.rpcSignatureCache.set(fn, acceptedParams);
541
- return acceptedParams;
542
- }
543
- };
544
- // Cache for RPC function signatures to avoid repeated database queries
545
- // Maps function name -> Set of parameter names it accepts
546
- _SecureSupabaseClient.rpcSignatureCache = /* @__PURE__ */ new Map();
547
- /**
548
- * RPC functions that are safe to call without organisation context.
549
- *
550
- * These functions must:
551
- * - rely on JWT context (auth.uid()) for authentication
552
- * - not read or write organisation-scoped data
553
- *
554
- * This allowlist enables compliant consuming apps to use `secureSupabase.rpc(...)`
555
- * even before an organisation is selected (common during initial page load/refresh).
556
- */
557
- _SecureSupabaseClient.GLOBAL_RPC_ALLOWLIST = /* @__PURE__ */ new Set([
558
- "data_rbac_apps_list"
559
- ]);
560
- var SecureSupabaseClient = _SecureSupabaseClient;
561
- function createSecureClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2 = false) {
562
- return new SecureSupabaseClient(supabaseUrl, supabaseKey, organisationId, eventId, appId, isSuperAdmin2);
563
- }
564
- function fromSupabaseClient(client, organisationId, eventId, appId, isSuperAdmin2 = false) {
565
- return new SecureSupabaseClient("", "", organisationId, eventId, appId, isSuperAdmin2, client);
566
- }
567
- function mapAccessLevelToEventRole(level) {
568
- switch (level) {
569
- case "viewer":
570
- return "viewer";
571
- case "participant":
572
- return "participant";
573
- case "planner":
574
- return "planner";
575
- case "admin":
576
- case "super":
577
- return "event_admin";
578
- default:
579
- return null;
580
- }
581
- }
582
- function useRBAC(pageId) {
583
- const logger2 = getRBACLogger();
584
- const {
585
- user,
586
- session,
587
- supabase,
588
- appName,
589
- appId: contextAppId,
590
- selectedOrganisation,
591
- isContextReady: orgContextReady,
592
- organisationLoading: orgLoading,
593
- selectedEvent,
594
- eventLoading
595
- } = useUnifiedAuth();
596
- const [globalRole, setGlobalRole] = useState(null);
597
- const [organisationRole, setOrganisationRole] = useState(null);
598
- const [eventAppRole, setEventAppRole] = useState(null);
599
- const [permissionMap, setPermissionMap] = useState({});
600
- const [currentScope, setCurrentScope] = useState(null);
601
- const [isLoading, setIsLoading] = useState(false);
602
- const [error, setError] = useState(null);
603
- const resetState = useCallback(() => {
604
- setGlobalRole(null);
605
- setOrganisationRole(null);
606
- setEventAppRole(null);
607
- setPermissionMap({});
608
- setCurrentScope(null);
609
- }, []);
610
- const loadRBACContext = useCallback(async () => {
611
- if (!user || !session) {
612
- resetState();
613
- setIsLoading(false);
614
- return;
615
- }
616
- const initialScope = {
617
- organisationId: selectedEvent?.organisation_id || selectedOrganisation?.id || void 0,
618
- eventId: selectedEvent?.event_id || void 0,
619
- appId: void 0
620
- };
621
- if (appName !== "PORTAL" && appName !== "ADMIN") {
622
- if (!selectedOrganisation && !selectedEvent) {
623
- setIsLoading(true);
624
- return;
625
- }
626
- }
627
- setIsLoading(true);
628
- setError(null);
629
- try {
630
- let appId = contextAppId;
631
- if (appName && !appId) {
632
- try {
633
- const resolved = await resolveAppContext({ userId: user.id, appName });
634
- if (!resolved) {
635
- if (appName === "PORTAL" || appName === "ADMIN") {
636
- } else {
637
- throw new Error(`User does not have access to app "${appName}"`);
638
- }
639
- } else if (!resolved.hasAccess && appName !== "PORTAL" && appName !== "ADMIN") {
640
- throw new Error(`User does not have access to app "${appName}"`);
641
- } else {
642
- appId = resolved.appId;
643
- }
644
- } catch (rpcError) {
645
- if (rpcError?.message?.includes("NetworkError") || rpcError?.message?.includes("fetch")) {
646
- logger2.warn("[useRBAC] NetworkError resolving app context - may be timing issue, will retry when context is ready", {
647
- appName,
648
- error: rpcError.message,
649
- eventLoading,
650
- hasSelectedEvent: !!selectedEvent
651
- });
652
- setIsLoading(false);
653
- return;
654
- }
655
- if (appName === "PORTAL" || appName === "ADMIN") {
656
- } else {
657
- throw rpcError;
658
- }
659
- }
660
- }
661
- const scope = {
662
- ...initialScope,
663
- appId: appId || contextAppId
664
- };
665
- let pageScopeType = "organisation";
666
- if (pageId && scope.appId) {
667
- try {
668
- pageScopeType = await getPageScopeType(pageId, scope.appId, appName);
669
- } catch (error2) {
670
- logger2.warn("[useRBAC] Failed to get page scope type, defaulting to organisation", {
671
- pageId,
672
- error: error2 instanceof Error ? error2.message : String(error2)
673
- });
674
- }
675
- }
676
- const validation = await ContextValidator.resolveScopeForPage(
677
- scope,
678
- pageScopeType,
679
- appName,
680
- supabase || null
681
- );
682
- if (!validation.isValid || !validation.resolvedScope) {
683
- throw validation.error || new Error("Context validation failed");
684
- }
685
- const resolvedScope = validation.resolvedScope;
686
- setCurrentScope(resolvedScope);
687
- const [map, roleContext, accessLevel] = await Promise.all([
688
- getPermissionMap({ userId: user.id, scope: resolvedScope }, appName),
689
- getRoleContext({ userId: user.id, scope: resolvedScope }, appName),
690
- getAccessLevel({ userId: user.id, scope: resolvedScope }, appName)
691
- ]);
692
- setPermissionMap(map);
693
- setGlobalRole(roleContext.globalRole);
694
- setOrganisationRole(roleContext.organisationRole);
695
- setEventAppRole(roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel));
696
- const permissionCount = Object.keys(map).length;
697
- if (permissionCount === 0) {
698
- logger2.warn("[useRBAC] RBAC context loaded but returned 0 permissions", {
699
- appName,
700
- organisationId: resolvedScope.organisationId,
701
- eventId: resolvedScope.eventId
702
- });
703
- }
704
- } catch (err) {
705
- const handledError = err instanceof Error ? err : new Error("Failed to load RBAC context");
706
- logger2.error("[useRBAC] Error loading RBAC context:", handledError);
707
- setError(handledError);
708
- resetState();
709
- } finally {
710
- setIsLoading(false);
711
- }
712
- }, [appName, logger2, resetState, selectedEvent?.event_id, selectedOrganisation?.id, session, user, eventLoading, orgContextReady, orgLoading]);
713
- const hasGlobalPermission = useCallback(
714
- (permission) => {
715
- if (globalRole === "super_admin" || permissionMap["*"]) {
716
- return true;
717
- }
718
- if (permission === "super_admin") {
719
- return globalRole === "super_admin";
720
- }
721
- if (permission === "org_admin") {
722
- return organisationRole === "org_admin";
723
- }
724
- return permissionMap[permission] === true;
725
- },
726
- [globalRole, organisationRole, permissionMap]
727
- );
728
- const isSuperAdmin2 = useMemo(() => globalRole === "super_admin" || permissionMap["*"] === true, [globalRole, permissionMap]);
729
- const isOrgAdmin = useMemo(() => organisationRole === "org_admin" || isSuperAdmin2, [organisationRole, isSuperAdmin2]);
730
- const isEventAdmin = useMemo(() => eventAppRole === "event_admin" || isSuperAdmin2, [eventAppRole, isSuperAdmin2]);
731
- const canManageOrganisation = useMemo(() => isSuperAdmin2 || organisationRole === "org_admin", [isSuperAdmin2, organisationRole]);
732
- const canManageEvent = useMemo(() => isSuperAdmin2 || eventAppRole === "event_admin", [isSuperAdmin2, eventAppRole]);
733
- useEffect(() => {
734
- loadRBACContext();
735
- }, [loadRBACContext, appName, eventLoading, selectedEvent?.event_id, user, session, selectedOrganisation?.id, orgContextReady, orgLoading]);
736
- return {
737
- user,
738
- globalRole,
739
- organisationRole,
740
- eventAppRole,
741
- hasGlobalPermission,
742
- isSuperAdmin: isSuperAdmin2,
743
- isOrgAdmin,
744
- isEventAdmin,
745
- canManageOrganisation,
746
- canManageEvent,
747
- isLoading,
748
- error
749
- };
750
- }
751
- var log = createLogger("useResolvedScope");
752
- var appIdCache = /* @__PURE__ */ new Map();
753
- var CACHE_TTL = 5 * 60 * 1e3;
754
- function useResolvedScope({
755
- supabase,
756
- selectedOrganisationId,
757
- selectedEventId,
758
- selectedEventOrganisationId
759
- }) {
760
- const immediateOrganisationId = selectedEventOrganisationId || selectedOrganisationId || void 0;
761
- const immediateEventId = selectedEventId || void 0;
762
- const [appId, setAppId] = useState(void 0);
763
- const [isResolvingAppId, setIsResolvingAppId] = useState(false);
764
- const [error, setError] = useState(null);
765
- const appName = getCurrentAppName();
766
- useEffect(() => {
767
- let cancelled = false;
768
- const resolveAppId = async () => {
769
- if (!supabase && !selectedOrganisationId && !selectedEventId) {
770
- if (!cancelled) {
771
- setAppId(void 0);
772
- setIsResolvingAppId(false);
773
- setError(null);
774
- }
775
- return;
776
- }
777
- setIsResolvingAppId(true);
778
- setError(null);
779
- try {
780
- const appName2 = getCurrentAppName();
781
- let resolvedAppId = void 0;
782
- if (supabase && appName2) {
783
- try {
784
- const { data: session } = await supabase.auth.getSession();
785
- if (!session?.session) {
786
- log.debug(`Skipping app resolution for "${appName2}" - user not authenticated`);
787
- } else {
788
- const cached = appIdCache.get(appName2);
789
- const now = Date.now();
790
- if (cached && now - cached.timestamp < CACHE_TTL) {
791
- resolvedAppId = cached.appId;
792
- } else {
793
- const { data: app, error: error2 } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).eq("is_active", true).single();
794
- if (error2) {
795
- if (error2.code === "406" || error2.code === "PGRST116" || error2.message?.includes("406")) {
796
- log.debug(`App resolution blocked by RLS for "${appName2}" - user may not be authenticated`);
797
- resolvedAppId = void 0;
798
- } else {
799
- const { data: inactiveApp } = await supabase.from("rbac_apps").select("id, name, is_active").eq("name", appName2).single();
800
- if (inactiveApp) {
801
- log.error(`App "${appName2}" exists but is inactive (is_active: ${inactiveApp.is_active})`);
802
- resolvedAppId = void 0;
803
- } else {
804
- log.error(`App "${appName2}" not found in rbac_apps table`, { error: error2 });
805
- resolvedAppId = void 0;
806
- }
807
- }
808
- } else if (app) {
809
- resolvedAppId = app.id;
810
- appIdCache.set(appName2, { appId: resolvedAppId, timestamp: now });
811
- }
812
- }
813
- }
814
- } catch (error2) {
815
- const errorMessage = error2 instanceof Error ? error2.message : String(error2);
816
- if (!errorMessage.includes("406") && !errorMessage.includes("PGRST116")) {
817
- log.error("Unexpected error resolving app ID:", error2);
818
- } else {
819
- log.debug("App resolution skipped - authentication required");
820
- }
821
- }
822
- }
823
- if (!cancelled) {
824
- setAppId(resolvedAppId);
825
- setIsResolvingAppId(false);
826
- setError(null);
827
- }
828
- } catch (err) {
829
- if (!cancelled) {
830
- setError(err);
831
- setIsResolvingAppId(false);
832
- }
833
- }
834
- };
835
- resolveAppId();
836
- return () => {
837
- cancelled = true;
838
- };
839
- }, [supabase, selectedOrganisationId, selectedEventId]);
840
- const immediateScope = useMemo(() => {
841
- if (appName === "PORTAL" || appName === "ADMIN") {
842
- return {
843
- organisationId: void 0,
844
- eventId: void 0,
845
- appId: appId || void 0
846
- };
847
- }
848
- const scope = {};
849
- if (immediateOrganisationId) {
850
- scope.organisationId = immediateOrganisationId;
851
- }
852
- if (immediateEventId) {
853
- scope.eventId = immediateEventId;
854
- }
855
- if (appId) {
856
- scope.appId = appId;
857
- }
858
- if (!scope.organisationId && !scope.appId) {
859
- return null;
860
- }
861
- return scope;
862
- }, [immediateOrganisationId, immediateEventId, appId, appName]);
863
- return {
864
- resolvedScope: immediateScope,
865
- isLoading: isResolvingAppId,
866
- // Only true while appId resolves
867
- error
868
- };
869
- }
870
- function useAccessLevel(userId, scope) {
871
- const [accessLevel, setAccessLevel] = useState("viewer");
872
- const [isLoading, setIsLoading] = useState(true);
873
- const [error, setError] = useState(null);
874
- const { appName } = useAppConfig();
875
- const fetchAccessLevel = useCallback(async () => {
876
- if (!userId) {
877
- setAccessLevel("viewer");
878
- setIsLoading(false);
879
- return;
880
- }
881
- try {
882
- setIsLoading(true);
883
- setError(null);
884
- const { isSuperAdmin: checkSuperAdmin } = await import('./api-7P7DI652.js');
885
- const isSuperAdminUser = await checkSuperAdmin(userId);
886
- if (isSuperAdminUser) {
887
- setAccessLevel("super");
888
- setIsLoading(false);
889
- return;
890
- }
891
- if (appName !== "PORTAL" && appName !== "ADMIN" && !scope.organisationId && !scope.eventId) {
892
- const orgError = new OrganisationContextRequiredError();
893
- setError(orgError);
894
- setAccessLevel("viewer");
895
- setIsLoading(false);
896
- return;
897
- }
898
- const level = await getAccessLevel({ userId, scope }, appName);
899
- setAccessLevel(level);
900
- } catch (err) {
901
- const error2 = err instanceof Error ? err : new Error("Failed to fetch access level");
902
- setError(error2);
903
- setAccessLevel("viewer");
904
- } finally {
905
- setIsLoading(false);
906
- }
907
- }, [userId, scope.organisationId, scope.eventId, scope.appId, appName]);
908
- useEffect(() => {
909
- fetchAccessLevel();
910
- }, [fetchAccessLevel]);
911
- return useMemo(() => ({
912
- accessLevel,
913
- isLoading,
914
- error,
915
- refetch: fetchAccessLevel
916
- }), [accessLevel, isLoading, error, fetchAccessLevel]);
917
- }
918
-
919
- // src/rbac/utils/deep-equal.ts
920
- function scopeEqual(a, b) {
921
- if (a === b) {
922
- return true;
923
- }
924
- if (a == null || b == null) {
925
- return a === b;
926
- }
927
- return a.organisationId === b.organisationId && a.eventId === b.eventId && a.appId === b.appId;
928
- }
929
-
930
- // src/rbac/hooks/permissions/useCan.ts
931
- function useCan(userId, scope, permission, pageId, useCache = true, precomputedSuperAdmin = null, appName) {
932
- const [isSuperAdmin2, setIsSuperAdmin] = useState(precomputedSuperAdmin ?? null);
933
- const initialCan = precomputedSuperAdmin === true ? true : false;
934
- const initialIsLoading = precomputedSuperAdmin === true ? false : true;
935
- const [can, setCan] = useState(initialCan);
936
- const [isLoading, setIsLoading] = useState(initialIsLoading);
937
- const [error, setError] = useState(null);
938
- const isValidScope = scope && typeof scope === "object";
939
- const organisationId = isValidScope ? scope.organisationId : void 0;
940
- const eventId = isValidScope ? scope.eventId : void 0;
941
- const appId = isValidScope ? scope.appId : void 0;
942
- useEffect(() => {
943
- if (precomputedSuperAdmin === true && isSuperAdmin2 !== true) {
944
- setIsSuperAdmin(true);
945
- setCan(true);
946
- setIsLoading(false);
947
- setError(null);
948
- } else if (precomputedSuperAdmin === false && isSuperAdmin2 !== false) {
949
- setIsSuperAdmin(false);
950
- }
951
- }, [precomputedSuperAdmin, isSuperAdmin2]);
952
- useEffect(() => {
953
- if (precomputedSuperAdmin === null) {
954
- if (!userId) {
955
- setIsSuperAdmin(false);
956
- return;
957
- }
958
- let cancelled = false;
959
- const checkSuperAdmin = async () => {
960
- const startTime = Date.now();
961
- try {
962
- const { isSuperAdmin: checkSuperAdmin2 } = await import('./api-7P7DI652.js');
963
- const timeoutWarning = setTimeout(() => {
964
- if (!cancelled) {
965
- console.warn("[useCan] Super admin check taking longer than 5 seconds", {
966
- userId,
967
- elapsedMs: Date.now() - startTime
968
- });
969
- }
970
- }, 5e3);
971
- const isSuper = await checkSuperAdmin2(userId);
972
- clearTimeout(timeoutWarning);
973
- if (!cancelled) {
974
- const elapsed = Date.now() - startTime;
975
- if (elapsed > 1e3) {
976
- console.warn("[useCan] Super admin check took longer than expected", {
977
- userId,
978
- elapsedMs: elapsed
979
- });
980
- }
981
- setIsSuperAdmin(isSuper);
982
- if (isSuper) {
983
- setCan(true);
984
- setIsLoading(false);
985
- setError(null);
986
- }
987
- }
988
- } catch (err) {
989
- if (!cancelled) {
990
- const elapsed = Date.now() - startTime;
991
- console.error("[useCan] Error checking super admin", {
992
- userId,
993
- error: err,
994
- elapsedMs: elapsed
995
- });
996
- setIsSuperAdmin(false);
997
- }
998
- }
999
- };
1000
- checkSuperAdmin();
1001
- return () => {
1002
- cancelled = true;
1003
- };
1004
- }
1005
- }, [userId, precomputedSuperAdmin]);
1006
- useEffect(() => {
1007
- const isPagePermission = permission.includes(":page.") || !!pageId;
1008
- const requiresOrgId = !isPagePermission;
1009
- if (isSuperAdmin2 === true) {
1010
- return;
1011
- }
1012
- if (requiresOrgId && (!isValidScope || !organisationId || organisationId === null || typeof organisationId === "string" && organisationId.trim() === "")) {
1013
- const timeoutId = setTimeout(() => {
1014
- setError(new Error("Organisation context is required for permission checks"));
1015
- setIsLoading(false);
1016
- setCan(false);
1017
- }, 3e3);
1018
- return () => clearTimeout(timeoutId);
1019
- }
1020
- if (error?.message === "Organisation context is required for permission checks") {
1021
- setError(null);
1022
- }
1023
- }, [isValidScope, organisationId, error, permission, pageId, isSuperAdmin2]);
1024
- const lastUserIdRef = useRef(null);
1025
- useRef(null);
1026
- const lastPermissionRef = useRef(null);
1027
- const lastPageIdRef = useRef(null);
1028
- const lastUseCacheRef = useRef(null);
1029
- const lastIsSuperAdminRef = useRef(null);
1030
- const stableScope = useMemo(() => {
1031
- if (!isValidScope) {
1032
- return null;
1033
- }
1034
- return {
1035
- organisationId,
1036
- eventId,
1037
- appId
1038
- };
1039
- }, [isValidScope, organisationId, eventId, appId]);
1040
- const prevScopeRef = useRef(null);
1041
- useEffect(() => {
1042
- const scopeChanged = !scopeEqual(prevScopeRef.current, stableScope);
1043
- const isSuperAdminChanged = lastIsSuperAdminRef.current !== isSuperAdmin2;
1044
- if (lastUserIdRef.current !== userId || scopeChanged || lastPermissionRef.current !== permission || lastPageIdRef.current !== pageId || lastUseCacheRef.current !== useCache || isSuperAdminChanged) {
1045
- lastIsSuperAdminRef.current = isSuperAdmin2;
1046
- lastUserIdRef.current = userId;
1047
- prevScopeRef.current = stableScope;
1048
- lastPermissionRef.current = permission;
1049
- lastPageIdRef.current = pageId;
1050
- lastUseCacheRef.current = useCache;
1051
- const checkPermission = async () => {
1052
- if (!userId) {
1053
- setCan(false);
1054
- setIsLoading(false);
1055
- return;
1056
- }
1057
- if (isSuperAdmin2 === true) {
1058
- setCan(true);
1059
- setIsLoading(false);
1060
- setError(null);
1061
- return;
1062
- }
1063
- if (isSuperAdmin2 === null) {
1064
- setIsLoading(true);
1065
- setCan(false);
1066
- setError(null);
1067
- return;
1068
- }
1069
- if (!isValidScope) {
1070
- setIsLoading(true);
1071
- setCan(false);
1072
- setError(null);
1073
- return;
1074
- }
1075
- const isPagePermission = permission.includes(":page.") || !!pageId;
1076
- const requiresOrgId = !isPagePermission;
1077
- const isPageName = pageId && typeof pageId === "string" && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(pageId);
1078
- const needsAppIdForPageName = isPagePermission && isPageName;
1079
- if (requiresOrgId && (!organisationId || organisationId === null || typeof organisationId === "string" && organisationId.trim() === "")) {
1080
- setIsLoading(true);
1081
- setCan(false);
1082
- setError(null);
1083
- return;
1084
- }
1085
- if (needsAppIdForPageName && (!appId || appId === null || typeof appId === "string" && appId.trim() === "")) {
1086
- setIsLoading(true);
1087
- setCan(false);
1088
- setError(null);
1089
- return;
1090
- }
1091
- try {
1092
- setIsLoading(true);
1093
- setError(null);
1094
- const validScope = {
1095
- ...organisationId ? { organisationId } : {},
1096
- ...eventId ? { eventId } : {},
1097
- ...appId ? { appId } : {}
1098
- };
1099
- const result = useCache ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName) : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, isSuperAdmin2 === false ? false : null);
1100
- setCan(result);
1101
- } catch (err) {
1102
- const logger2 = getRBACLogger();
1103
- logger2.error("Permission check error:", { permission, error: err });
1104
- console.error("[useCan] Permission check error", { userId, permission, error: err });
1105
- setError(err instanceof Error ? err : new Error("Failed to check permission"));
1106
- setCan(false);
1107
- } finally {
1108
- setIsLoading(false);
1109
- }
1110
- };
1111
- checkPermission();
1112
- }
1113
- }, [userId, stableScope, permission, pageId, useCache, appName, isSuperAdmin2]);
1114
- const refetch = useCallback(async () => {
1115
- if (!userId) {
1116
- setCan(false);
1117
- setIsLoading(false);
1118
- return;
1119
- }
1120
- if (!isValidScope) {
1121
- setCan(false);
1122
- setIsLoading(true);
1123
- setError(null);
1124
- return;
1125
- }
1126
- const isPagePermission = permission.includes(":page.") || !!pageId;
1127
- const requiresOrgId = !isPagePermission;
1128
- if (requiresOrgId && (!organisationId || organisationId === null || typeof organisationId === "string" && organisationId.trim() === "")) {
1129
- setCan(false);
1130
- setIsLoading(true);
1131
- setError(null);
1132
- return;
1133
- }
1134
- try {
1135
- setIsLoading(true);
1136
- setError(null);
1137
- const validScope = {
1138
- ...organisationId ? { organisationId } : {},
1139
- ...eventId ? { eventId } : {},
1140
- ...appId ? { appId } : {}
1141
- };
1142
- const result = useCache ? await isPermittedCached({ userId, scope: validScope, permission, pageId }, appName) : await isPermitted({ userId, scope: validScope, permission, pageId }, appName, null);
1143
- setCan(result);
1144
- } catch (err) {
1145
- setError(err instanceof Error ? err : new Error("Failed to check permission"));
1146
- setCan(false);
1147
- } finally {
1148
- setIsLoading(false);
1149
- }
1150
- }, [userId, isValidScope, organisationId, eventId, appId, permission, pageId, useCache, appName]);
1151
- return useMemo(() => ({
1152
- can,
1153
- isLoading,
1154
- error,
1155
- refetch
1156
- }), [can, isLoading, error, refetch]);
1157
- }
1158
- function useMultiplePermissions(userId, scope, permissions, useCache = true) {
1159
- const [results, setResults] = useState({});
1160
- const [isLoading, setIsLoading] = useState(true);
1161
- const [error, setError] = useState(null);
1162
- const checkPermissions = useCallback(async () => {
1163
- if (!userId || permissions.length === 0) {
1164
- setResults({});
1165
- setIsLoading(false);
1166
- return;
1167
- }
1168
- try {
1169
- setIsLoading(true);
1170
- setError(null);
1171
- const permissionResults = {};
1172
- for (const permission of permissions) {
1173
- const result = useCache ? await isPermittedCached({ userId, scope, permission }) : await isPermitted({ userId, scope, permission });
1174
- permissionResults[permission] = result;
1175
- }
1176
- setResults(permissionResults);
1177
- } catch (err) {
1178
- setError(err instanceof Error ? err : new Error("Failed to check permissions"));
1179
- setResults({});
1180
- } finally {
1181
- setIsLoading(false);
1182
- }
1183
- }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);
1184
- useEffect(() => {
1185
- checkPermissions();
1186
- }, [checkPermissions]);
1187
- return useMemo(() => ({
1188
- results,
1189
- isLoading,
1190
- error,
1191
- refetch: checkPermissions
1192
- }), [results, isLoading, error, checkPermissions]);
1193
- }
1194
- function usePermissions(userId, organisationId, eventId, appId) {
1195
- const [permissions, setPermissions] = useState({});
1196
- const [isLoading, setIsLoading] = useState(true);
1197
- const [error, setError] = useState(null);
1198
- const [fetchTrigger, setFetchTrigger] = useState(0);
1199
- const isFetchingRef = useRef(false);
1200
- const logger2 = getRBACLogger();
1201
- const prevValuesRef = useRef({ userId, organisationId, eventId, appId });
1202
- const orgId = organisationId || "";
1203
- useEffect(() => {
1204
- if (!userId) {
1205
- return;
1206
- }
1207
- if (!orgId || orgId === null || typeof orgId === "string" && orgId.trim() === "") {
1208
- const timeoutId = setTimeout(() => {
1209
- setError(new Error("Organisation context is required for permission checks"));
1210
- setIsLoading(false);
1211
- }, 3e3);
1212
- return () => clearTimeout(timeoutId);
1213
- }
1214
- if (error?.message === "Organisation context is required for permission checks") {
1215
- setError(null);
1216
- }
1217
- }, [userId, organisationId, error, orgId]);
1218
- useEffect(() => {
1219
- const paramsChanged = prevValuesRef.current.userId !== userId || prevValuesRef.current.organisationId !== organisationId || prevValuesRef.current.eventId !== eventId || prevValuesRef.current.appId !== appId;
1220
- if (paramsChanged) {
1221
- if (prevValuesRef.current.appId !== appId) ;
1222
- prevValuesRef.current = { userId, organisationId, eventId, appId };
1223
- setFetchTrigger((prev) => prev + 1);
1224
- }
1225
- }, [userId, organisationId, eventId, appId, logger2]);
1226
- useEffect(() => {
1227
- const fetchPermissions = async () => {
1228
- if (isFetchingRef.current) {
1229
- return;
1230
- }
1231
- if (!userId) {
1232
- setPermissions({});
1233
- setIsLoading(false);
1234
- return;
1235
- }
1236
- if (!userId) {
1237
- setPermissions({});
1238
- setIsLoading(false);
1239
- return;
1240
- }
1241
- if (!orgId || orgId === null || typeof orgId === "string" && orgId.trim() === "") {
1242
- setIsLoading(true);
1243
- setError(null);
1244
- return;
1245
- }
1246
- try {
1247
- isFetchingRef.current = true;
1248
- setIsLoading(true);
1249
- setError(null);
1250
- const scope = {
1251
- organisationId: orgId,
1252
- eventId,
1253
- appId
1254
- };
1255
- const permissionMap = await getPermissionMap({ userId, scope });
1256
- const permissionCount = Object.keys(permissionMap).length;
1257
- if (permissionCount === 0 && Object.keys(permissions).length > 0) {
1258
- logger2.warn("[usePermissions] Permissions fetched but returned empty map", {
1259
- scope: { organisationId: orgId, eventId, appId }
1260
- });
1261
- }
1262
- setPermissions(permissionMap);
1263
- } catch (err) {
1264
- logger2.error("[usePermissions] Failed to fetch permissions:", err);
1265
- setError(err instanceof Error ? err : new Error("Failed to fetch permissions"));
1266
- } finally {
1267
- setIsLoading(false);
1268
- isFetchingRef.current = false;
1269
- }
1270
- };
1271
- fetchPermissions();
1272
- }, [fetchTrigger, userId, organisationId, eventId, appId]);
1273
- const hasPermission = useCallback((permission) => {
1274
- if (permissions["*"]) {
1275
- return true;
1276
- }
1277
- return permissions[permission] === true;
1278
- }, [permissions]);
1279
- const hasAnyPermission = useCallback((permissionList) => {
1280
- if (permissions["*"]) {
1281
- return true;
1282
- }
1283
- return permissionList.some((p) => permissions[p] === true);
1284
- }, [permissions]);
1285
- const hasAllPermissions = useCallback((permissionList) => {
1286
- if (permissions["*"]) {
1287
- return true;
1288
- }
1289
- return permissionList.every((p) => permissions[p] === true);
1290
- }, [permissions]);
1291
- const refetch = useCallback(async () => {
1292
- if (isFetchingRef.current) {
1293
- return;
1294
- }
1295
- if (!userId) {
1296
- setPermissions({});
1297
- setIsLoading(false);
1298
- return;
1299
- }
1300
- if (!orgId || orgId === null || typeof orgId === "string" && orgId.trim() === "") {
1301
- setIsLoading(true);
1302
- setError(null);
1303
- return;
1304
- }
1305
- try {
1306
- isFetchingRef.current = true;
1307
- setIsLoading(true);
1308
- setError(null);
1309
- const scope = {
1310
- organisationId: orgId,
1311
- eventId,
1312
- appId
1313
- };
1314
- const permissionMap = await getPermissionMap({ userId, scope });
1315
- setPermissions(permissionMap);
1316
- } catch (err) {
1317
- const logger3 = getRBACLogger();
1318
- logger3.error("Failed to refetch permissions:", err);
1319
- setError(err instanceof Error ? err : new Error("Failed to fetch permissions"));
1320
- } finally {
1321
- setIsLoading(false);
1322
- isFetchingRef.current = false;
1323
- }
1324
- }, [userId, organisationId, eventId, appId]);
1325
- return useMemo(() => ({
1326
- permissions,
1327
- isLoading,
1328
- error,
1329
- hasPermission,
1330
- hasAnyPermission,
1331
- hasAllPermissions,
1332
- refetch
1333
- }), [permissions, isLoading, error, hasPermission, hasAnyPermission, hasAllPermissions, refetch]);
1334
- }
1335
- function useResourcePermissions(resource, options = {}) {
1336
- const { enableRead = false, requireScope = true } = options;
1337
- const logger2 = createLogger("ResourcePermissions");
1338
- const { user, supabase } = useUnifiedAuth();
1339
- const [isSuperAdminUser, setIsSuperAdminUser] = useState(null);
1340
- const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(() => !!user?.id);
1341
- const lastCheckedUserIdRef = useRef(null);
1342
- const isCheckingRef = useRef(false);
1343
- useEffect(() => {
1344
- if (lastCheckedUserIdRef.current === user?.id && isSuperAdminUser !== null) {
1345
- return;
1346
- }
1347
- if (isCheckingRef.current) {
1348
- return;
1349
- }
1350
- const checkSuperAdminStatus = async () => {
1351
- if (!user?.id) {
1352
- setIsSuperAdminUser(false);
1353
- setIsCheckingSuperAdmin(false);
1354
- lastCheckedUserIdRef.current = null;
1355
- return;
1356
- }
1357
- isCheckingRef.current = true;
1358
- lastCheckedUserIdRef.current = user.id;
1359
- const startTime = Date.now();
1360
- setIsCheckingSuperAdmin(true);
1361
- const timeoutId = setTimeout(() => {
1362
- logger2.warn("useResourcePermissions", "Super admin check taking longer than 5 seconds", {
1363
- userId: user?.id,
1364
- elapsedMs: Date.now() - startTime
1365
- });
1366
- }, 5e3);
1367
- try {
1368
- const superAdminStatus = await isSuperAdmin(user.id);
1369
- setIsSuperAdminUser(superAdminStatus);
1370
- } catch (error2) {
1371
- const elapsed = Date.now() - startTime;
1372
- logger2.error("useResourcePermissions", "Error checking super admin status", {
1373
- userId: user?.id,
1374
- error: error2,
1375
- elapsedMs: elapsed
1376
- });
1377
- setIsSuperAdminUser(false);
1378
- } finally {
1379
- clearTimeout(timeoutId);
1380
- setIsCheckingSuperAdmin(false);
1381
- isCheckingRef.current = false;
1382
- }
1383
- };
1384
- checkSuperAdminStatus();
1385
- }, [user?.id, logger2]);
1386
- const { selectedOrganisation } = useOrganisations();
1387
- let selectedEvent = null;
1388
- try {
1389
- const eventsContext = useEvents();
1390
- selectedEvent = eventsContext.selectedEvent;
1391
- } catch (error2) {
1392
- }
1393
- const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
1394
- supabase,
1395
- selectedOrganisationId: selectedOrganisation?.id || null,
1396
- selectedEventId: selectedEvent?.event_id || null,
1397
- selectedEventOrganisationId: selectedEvent?.organisation_id || null
1398
- });
1399
- const scope = resolvedScope || {
1400
- organisationId: selectedOrganisation?.id || "",
1401
- eventId: selectedEvent?.event_id || void 0,
1402
- appId: void 0
1403
- };
1404
- const hasAppId = !!resolvedScope?.appId;
1405
- const pageId = hasAppId ? resource : void 0;
1406
- const isPagePermission = hasAppId && !!pageId;
1407
- const createPermission = isPagePermission ? `create:page.${resource}` : `create:${resource}`;
1408
- const updatePermission = isPagePermission ? `update:page.${resource}` : `update:${resource}`;
1409
- const deletePermission = isPagePermission ? `delete:page.${resource}` : `delete:${resource}`;
1410
- const readPermission = isPagePermission ? `read:page.${resource}` : `read:${resource}`;
1411
- const { can: canCreateResult, isLoading: createLoading, error: createError } = useCan(
1412
- user?.id || "",
1413
- scope,
1414
- createPermission,
1415
- pageId,
1416
- // Pass resource name as pageId when appId is available to enable page permission checks
1417
- true,
1418
- // useCache
1419
- isSuperAdminUser,
1420
- // precomputedSuperAdmin - null if checking, false/true if checked
1421
- void 0
1422
- // appName
1423
- );
1424
- const { can: canUpdateResult, isLoading: updateLoading, error: updateError } = useCan(
1425
- user?.id || "",
1426
- scope,
1427
- updatePermission,
1428
- pageId,
1429
- // Pass resource name as pageId when appId is available to enable page permission checks
1430
- true,
1431
- // useCache
1432
- isSuperAdminUser,
1433
- // precomputedSuperAdmin - null if checking, false/true if checked
1434
- void 0
1435
- // appName
1436
- );
1437
- const { can: canDeleteResult, isLoading: deleteLoading, error: deleteError } = useCan(
1438
- user?.id || "",
1439
- scope,
1440
- deletePermission,
1441
- pageId,
1442
- // Pass resource name as pageId when appId is available to enable page permission checks
1443
- true,
1444
- // useCache
1445
- isSuperAdminUser,
1446
- // precomputedSuperAdmin - null if checking, false/true if checked
1447
- void 0
1448
- // appName
1449
- );
1450
- const { can: canReadResult, isLoading: readLoading, error: readError } = useCan(
1451
- user?.id || "",
1452
- scope,
1453
- readPermission,
1454
- pageId,
1455
- // Pass resource name as pageId when appId is available to enable page permission checks
1456
- true,
1457
- // useCache
1458
- isSuperAdminUser,
1459
- // precomputedSuperAdmin - null if checking, false/true if checked
1460
- void 0
1461
- // appName
1462
- );
1463
- const isLoading = useMemo(() => {
1464
- const waitingForScope = requireScope && scopeLoading;
1465
- const waitingForSuperAdmin = isSuperAdminUser === null && isCheckingSuperAdmin;
1466
- return waitingForScope || waitingForSuperAdmin || createLoading || updateLoading || deleteLoading || enableRead && readLoading;
1467
- }, [scopeLoading, requireScope, isSuperAdminUser, isCheckingSuperAdmin, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
1468
- const error = useMemo(() => {
1469
- if (scopeError) return scopeError;
1470
- if (createError) return createError;
1471
- if (updateError) return updateError;
1472
- if (deleteError) return deleteError;
1473
- if (enableRead && readError) return readError;
1474
- return null;
1475
- }, [scopeError, createError, updateError, deleteError, readError, enableRead]);
1476
- return useMemo(() => {
1477
- const createSuperAdminAwarePermission = (result) => {
1478
- if (isSuperAdminUser === true) {
1479
- return true;
1480
- }
1481
- return result;
1482
- };
1483
- return {
1484
- canCreate: (res) => {
1485
- if (res !== resource) {
1486
- return false;
1487
- }
1488
- return createSuperAdminAwarePermission(canCreateResult);
1489
- },
1490
- canUpdate: (res) => {
1491
- if (res !== resource) {
1492
- return false;
1493
- }
1494
- return createSuperAdminAwarePermission(canUpdateResult);
1495
- },
1496
- canDelete: (res) => {
1497
- if (res !== resource) {
1498
- return false;
1499
- }
1500
- return createSuperAdminAwarePermission(canDeleteResult);
1501
- },
1502
- canRead: (res) => {
1503
- if (!enableRead) {
1504
- return true;
1505
- }
1506
- if (res !== resource) {
1507
- return false;
1508
- }
1509
- return createSuperAdminAwarePermission(canReadResult);
1510
- },
1511
- scope,
1512
- isLoading: isCheckingSuperAdmin || isLoading,
1513
- error
1514
- };
1515
- }, [
1516
- resource,
1517
- isSuperAdminUser,
1518
- isCheckingSuperAdmin,
1519
- canCreateResult,
1520
- canUpdateResult,
1521
- canDeleteResult,
1522
- canReadResult,
1523
- enableRead,
1524
- scope,
1525
- isLoading,
1526
- error
1527
- ]);
1528
- }
1529
- function useRoleManagement() {
1530
- const { user, supabase } = useUnifiedAuth();
1531
- const [isLoading, setIsLoading] = useState(false);
1532
- const [error, setError] = useState(null);
1533
- if (!supabase) {
1534
- throw new Error("useRoleManagement requires a Supabase client. Ensure UnifiedAuthProvider is configured.");
1535
- }
1536
- const revokeEventAppRole = useCallback(async (params) => {
1537
- setIsLoading(true);
1538
- setError(null);
1539
- try {
1540
- const contextId = `${params.event_id}:${params.app_id}`;
1541
- const rpcParams = {
1542
- p_user_id: params.user_id,
1543
- p_role_type: "event_app",
1544
- p_role_name: params.role,
1545
- p_context_id: contextId,
1546
- p_revoked_by: params.revoked_by || user?.id || void 0
1547
- };
1548
- if (import.meta.env.MODE === "development") {
1549
- console.log("[useRoleManagement] revokeEventAppRole called with:", rpcParams);
1550
- }
1551
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", rpcParams);
1552
- if (rpcError) {
1553
- if (import.meta.env.MODE === "development") {
1554
- console.error("[useRoleManagement] RPC error:", {
1555
- message: rpcError.message,
1556
- details: rpcError.details,
1557
- hint: rpcError.hint,
1558
- code: rpcError.code,
1559
- fullError: rpcError
1560
- });
1561
- }
1562
- const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
1563
- throw new Error(errorMessage);
1564
- }
1565
- if (import.meta.env.MODE === "development") {
1566
- console.log("[useRoleManagement] RPC response:", {
1567
- data,
1568
- error: rpcError,
1569
- dataType: Array.isArray(data) ? "array" : typeof data,
1570
- dataLength: Array.isArray(data) ? data.length : "N/A"
1571
- });
1572
- }
1573
- if (!data || !Array.isArray(data) || data.length === 0) {
1574
- const errorMsg = "No response from database - role revocation may have failed";
1575
- if (import.meta.env.MODE === "development") {
1576
- console.error("[useRoleManagement] Empty or null data response:", {
1577
- data,
1578
- dataType: typeof data,
1579
- isArray: Array.isArray(data),
1580
- length: Array.isArray(data) ? data.length : "N/A"
1581
- });
1582
- }
1583
- throw new Error(errorMsg);
1584
- }
1585
- const result = data[0];
1586
- if (import.meta.env.MODE === "development") {
1587
- console.log("[useRoleManagement] RPC result:", {
1588
- success: result?.success,
1589
- message: result?.message,
1590
- error_code: result?.error_code,
1591
- revoked_count: result?.revoked_count,
1592
- fullResult: result
1593
- });
1594
- }
1595
- if (!result || result.success !== true) {
1596
- const errorMessage = result?.message || result?.error_code || "Role revocation failed";
1597
- if (import.meta.env.MODE === "development") {
1598
- console.error("[useRoleManagement] Role revocation failed:", {
1599
- result,
1600
- errorMessage,
1601
- fullData: data,
1602
- rpcParams
1603
- });
1604
- }
1605
- return {
1606
- success: false,
1607
- message: result?.message || void 0,
1608
- error: errorMessage
1609
- };
1610
- }
1611
- return {
1612
- success: true,
1613
- message: result.message || "Role revoked successfully",
1614
- error: void 0
1615
- };
1616
- } catch (err) {
1617
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1618
- if (import.meta.env.MODE === "development") {
1619
- console.error("[useRoleManagement] Exception in revokeEventAppRole:", {
1620
- error: err,
1621
- errorMessage,
1622
- params
1623
- });
1624
- }
1625
- setError(err instanceof Error ? err : new Error(errorMessage));
1626
- return {
1627
- success: false,
1628
- error: errorMessage
1629
- };
1630
- } finally {
1631
- setIsLoading(false);
1632
- }
1633
- }, [user?.id, supabase]);
1634
- const grantEventAppRole = useCallback(async (params) => {
1635
- setIsLoading(true);
1636
- setError(null);
1637
- try {
1638
- const { data, error: rpcError } = await supabase.rpc("grant_event_app_role", {
1639
- p_user_id: params.user_id,
1640
- p_organisation_id: params.organisation_id,
1641
- p_event_id: params.event_id,
1642
- p_app_id: params.app_id,
1643
- p_role: params.role,
1644
- p_granted_by: params.granted_by || user?.id || void 0,
1645
- p_valid_from: params.valid_from,
1646
- p_valid_to: params.valid_to
1647
- });
1648
- if (rpcError) {
1649
- throw new Error(rpcError.message || "Failed to grant role");
1650
- }
1651
- if (!data) {
1652
- return {
1653
- success: false,
1654
- error: "Failed to grant role - no role ID returned"
1655
- };
1656
- }
1657
- return {
1658
- success: true,
1659
- message: "Role granted successfully",
1660
- roleId: data
1661
- };
1662
- } catch (err) {
1663
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1664
- setError(err instanceof Error ? err : new Error(errorMessage));
1665
- return {
1666
- success: false,
1667
- error: errorMessage
1668
- };
1669
- } finally {
1670
- setIsLoading(false);
1671
- }
1672
- }, [user?.id]);
1673
- const revokeRoleById = useCallback(async (roleId) => {
1674
- setIsLoading(true);
1675
- setError(null);
1676
- try {
1677
- const { data: roleData, error: fetchError } = await supabase.from("rbac_event_app_roles").select("user_id, role, event_id, app_id").eq("id", roleId).single();
1678
- if (fetchError || !roleData) {
1679
- throw new Error(fetchError?.message || "Role not found");
1680
- }
1681
- const contextId = `${roleData.event_id}:${roleData.app_id}`;
1682
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
1683
- p_user_id: roleData.user_id,
1684
- p_role_type: "event_app",
1685
- p_role_name: roleData.role,
1686
- p_context_id: contextId,
1687
- p_revoked_by: user?.id || void 0
1688
- });
1689
- if (rpcError) {
1690
- const errorMessage = rpcError.message || "Failed to revoke role - unknown RPC error";
1691
- throw new Error(errorMessage);
1692
- }
1693
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1694
- if (!result) {
1695
- return {
1696
- success: false,
1697
- error: void 0
1698
- };
1699
- }
1700
- if (result.success === false) {
1701
- const errorMessage = result.message || result.error_code || "Role revocation failed";
1702
- return {
1703
- success: false,
1704
- message: result.message || void 0,
1705
- error: errorMessage
1706
- };
1707
- }
1708
- return {
1709
- success: true,
1710
- message: result.message || "Role revoked successfully",
1711
- error: void 0
1712
- };
1713
- } catch (err) {
1714
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1715
- setError(err instanceof Error ? err : new Error(errorMessage));
1716
- return {
1717
- success: false,
1718
- error: errorMessage
1719
- };
1720
- } finally {
1721
- setIsLoading(false);
1722
- }
1723
- }, [user?.id, supabase]);
1724
- const grantGlobalRole = useCallback(async (params) => {
1725
- setIsLoading(true);
1726
- setError(null);
1727
- try {
1728
- const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", {
1729
- p_user_id: params.user_id,
1730
- p_role_type: "global",
1731
- p_role_name: params.role,
1732
- p_context_id: null,
1733
- // Global roles don't need context
1734
- p_granted_by: params.granted_by || user?.id || void 0
1735
- });
1736
- if (rpcError) {
1737
- throw new Error(rpcError.message || "Failed to grant role");
1738
- }
1739
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1740
- if (!result || !result.success) {
1741
- return {
1742
- success: false,
1743
- error: result?.message || result?.error_code || "Failed to grant role",
1744
- message: result?.message
1745
- };
1746
- }
1747
- return {
1748
- success: true,
1749
- message: result.message || "Role granted successfully",
1750
- roleId: result.role_id
1751
- };
1752
- } catch (err) {
1753
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1754
- setError(err instanceof Error ? err : new Error(errorMessage));
1755
- return {
1756
- success: false,
1757
- error: errorMessage
1758
- };
1759
- } finally {
1760
- setIsLoading(false);
1761
- }
1762
- }, [user?.id, supabase]);
1763
- const revokeGlobalRole = useCallback(async (params) => {
1764
- setIsLoading(true);
1765
- setError(null);
1766
- try {
1767
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
1768
- p_user_id: params.user_id,
1769
- p_role_type: "global",
1770
- p_role_name: params.role,
1771
- p_context_id: null,
1772
- // Global roles don't need context
1773
- p_revoked_by: params.revoked_by || user?.id || void 0
1774
- });
1775
- if (rpcError) {
1776
- const errorParts = [
1777
- rpcError.message,
1778
- rpcError.details,
1779
- rpcError.hint,
1780
- rpcError.code ? `Error code: ${rpcError.code}` : null
1781
- ].filter(Boolean);
1782
- const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
1783
- throw new Error(errorMessage);
1784
- }
1785
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1786
- return {
1787
- success: result?.success === true,
1788
- message: result?.message || void 0,
1789
- error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
1790
- };
1791
- } catch (err) {
1792
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1793
- setError(err instanceof Error ? err : new Error(errorMessage));
1794
- return {
1795
- success: false,
1796
- error: errorMessage
1797
- };
1798
- } finally {
1799
- setIsLoading(false);
1800
- }
1801
- }, [user?.id, supabase]);
1802
- const grantOrganisationRole = useCallback(async (params) => {
1803
- setIsLoading(true);
1804
- setError(null);
1805
- try {
1806
- const { data, error: rpcError } = await supabase.rpc("rbac_role_grant", {
1807
- p_user_id: params.user_id,
1808
- p_role_type: "organisation",
1809
- p_role_name: params.role,
1810
- p_context_id: params.organisation_id,
1811
- // Organisation ID as context
1812
- p_granted_by: params.granted_by || user?.id || void 0
1813
- });
1814
- if (rpcError) {
1815
- throw new Error(rpcError.message || "Failed to grant role");
1816
- }
1817
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1818
- if (!result || !result.success) {
1819
- return {
1820
- success: false,
1821
- error: result?.message || result?.error_code || "Failed to grant role",
1822
- message: result?.message
1823
- };
1824
- }
1825
- return {
1826
- success: true,
1827
- message: result.message || "Role granted successfully",
1828
- roleId: result.role_id
1829
- };
1830
- } catch (err) {
1831
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1832
- setError(err instanceof Error ? err : new Error(errorMessage));
1833
- return {
1834
- success: false,
1835
- error: errorMessage
1836
- };
1837
- } finally {
1838
- setIsLoading(false);
1839
- }
1840
- }, [user?.id, supabase]);
1841
- const revokeOrganisationRole = useCallback(async (params) => {
1842
- setIsLoading(true);
1843
- setError(null);
1844
- try {
1845
- const { data, error: rpcError } = await supabase.rpc("rbac_role_revoke", {
1846
- p_user_id: params.user_id,
1847
- p_role_type: "organisation",
1848
- p_role_name: params.role,
1849
- p_context_id: params.organisation_id,
1850
- // Organisation ID as context
1851
- p_revoked_by: params.revoked_by || user?.id || void 0
1852
- });
1853
- if (rpcError) {
1854
- const errorParts = [
1855
- rpcError.message,
1856
- rpcError.details,
1857
- rpcError.hint,
1858
- rpcError.code ? `Error code: ${rpcError.code}` : null
1859
- ].filter(Boolean);
1860
- const errorMessage = errorParts.length > 0 ? errorParts.join(" | ") : "Failed to revoke role - unknown RPC error";
1861
- throw new Error(errorMessage);
1862
- }
1863
- const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
1864
- return {
1865
- success: result?.success === true,
1866
- message: result?.message || void 0,
1867
- error: result?.success === false ? result?.message || result?.error_code || "Unknown error" : void 0
1868
- };
1869
- } catch (err) {
1870
- const errorMessage = err instanceof Error ? err.message : "Unknown error occurred";
1871
- setError(err instanceof Error ? err : new Error(errorMessage));
1872
- return {
1873
- success: false,
1874
- error: errorMessage
1875
- };
1876
- } finally {
1877
- setIsLoading(false);
1878
- }
1879
- }, [user?.id, supabase]);
1880
- return {
1881
- // Event app roles (existing)
1882
- revokeEventAppRole,
1883
- grantEventAppRole,
1884
- revokeRoleById,
1885
- // Global roles (new)
1886
- grantGlobalRole,
1887
- revokeGlobalRole,
1888
- // Organisation roles (new)
1889
- grantOrganisationRole,
1890
- revokeOrganisationRole,
1891
- // Shared state
1892
- isLoading,
1893
- error
1894
- };
1895
- }
1896
- var secureClientCache = /* @__PURE__ */ new Map();
1897
- var MAX_CACHE_SIZE = 5;
1898
- function getCacheKey(organisationId, eventId, appId, isSuperAdmin2) {
1899
- return `${organisationId || "no-org"}-${eventId || "no-event"}-${appId || "no-app"}-${isSuperAdmin2 ? "super" : "regular"}`;
1900
- }
1901
- function getSupabaseConfig() {
1902
- const getEnvVar = (key) => {
1903
- if (typeof import.meta !== "undefined" && import.meta.env) {
1904
- return import.meta.env[key];
1905
- }
1906
- if (typeof process !== "undefined" && process.env) {
1907
- return process.env[key];
1908
- }
1909
- return void 0;
1910
- };
1911
- const supabaseUrl = getEnvVar("VITE_SUPABASE_URL") || getEnvVar("NEXT_PUBLIC_SUPABASE_URL") || null;
1912
- const supabaseKey = getEnvVar("VITE_SUPABASE_PUBLISHABLE_KEY") || getEnvVar("NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY") || null;
1913
- if (!supabaseUrl || !supabaseKey) {
1914
- return null;
1915
- }
1916
- return { url: supabaseUrl, key: supabaseKey };
1917
- }
1918
- function useSecureSupabase(baseClient) {
1919
- const { user, supabase: authSupabase } = useUnifiedAuth();
1920
- const { selectedOrganisation } = useOrganisations();
1921
- const eventsContext = useEvents();
1922
- const { selectedEvent } = eventsContext;
1923
- const eventLoading = "eventLoading" in eventsContext ? eventsContext.eventLoading : false;
1924
- const { superAdminContext } = useOrganisationSecurity();
1925
- const isSuperAdmin2 = superAdminContext.isSuperAdmin;
1926
- const { resolvedScope } = useResolvedScope({
1927
- supabase: authSupabase || null,
1928
- selectedOrganisationId: selectedOrganisation?.id || null,
1929
- selectedEventId: selectedEvent?.event_id || null,
1930
- selectedEventOrganisationId: selectedEvent?.organisation_id || null
1931
- });
1932
- const prevContextRef = useRef({
1933
- organisationId: void 0,
1934
- eventId: void 0,
1935
- appId: void 0
1936
- });
1937
- return useMemo(() => {
1938
- const organisationId = resolvedScope?.organisationId;
1939
- const eventId = resolvedScope?.eventId || selectedEvent?.event_id;
1940
- const appId = resolvedScope?.appId;
1941
- const canCreateSecureClient = user?.id && (isSuperAdmin2 || organisationId);
1942
- if (canCreateSecureClient) {
1943
- prevContextRef.current = { organisationId, eventId, appId };
1944
- const cacheKey = getCacheKey(organisationId, eventId, appId, isSuperAdmin2);
1945
- const cachedClient = secureClientCache.get(cacheKey);
1946
- if (cachedClient) {
1947
- return cachedClient.getClient();
1948
- }
1949
- const config = getSupabaseConfig();
1950
- if (!config || !config.url || !config.key) {
1951
- logger.warn("useSecureSupabase", "Missing Supabase environment variables. Falling back to base client.", {
1952
- note: "Ensure VITE_SUPABASE_URL and VITE_SUPABASE_PUBLISHABLE_KEY are set in your environment."
1953
- });
1954
- return baseClient || authSupabase || null;
1955
- }
1956
- try {
1957
- const effectiveOrganisationId = isSuperAdmin2 ? organisationId || null : organisationId;
1958
- const baseForSecureClient = baseClient || authSupabase || null;
1959
- const secureClient = baseForSecureClient ? fromSupabaseClient(
1960
- baseForSecureClient,
1961
- effectiveOrganisationId ?? null,
1962
- eventId,
1963
- appId,
1964
- isSuperAdmin2
1965
- ) : createSecureClient(
1966
- config.url,
1967
- config.key,
1968
- effectiveOrganisationId,
1969
- // organisationId is string | null, UUID is string alias
1970
- eventId,
1971
- appId,
1972
- // appId is string | undefined, UUID is string alias
1973
- isSuperAdmin2
1974
- // Pass super admin status for conditional filtering
1975
- );
1976
- secureClientCache.set(cacheKey, secureClient);
1977
- if (secureClientCache.size > MAX_CACHE_SIZE) {
1978
- const firstKey = secureClientCache.keys().next().value;
1979
- if (firstKey) {
1980
- secureClientCache.delete(firstKey);
1981
- }
1982
- }
1983
- return secureClient.getClient();
1984
- } catch (error) {
1985
- logger.error("useSecureSupabase", "Failed to create secure client", error);
1986
- return baseClient || authSupabase || null;
1987
- }
1988
- }
1989
- return baseClient || authSupabase || null;
1990
- }, [
1991
- resolvedScope?.organisationId,
1992
- resolvedScope?.eventId,
1993
- resolvedScope?.appId,
1994
- selectedEvent?.event_id,
1995
- user?.id,
1996
- eventLoading,
1997
- isSuperAdmin2,
1998
- baseClient,
1999
- authSupabase
2000
- ]);
2001
- }
2002
-
2003
- export { Button, ButtonGroup, SECURE_CLIENT_SYMBOL, SecureSupabaseClient, Tooltip, TooltipContent, TooltipProvider, TooltipRoot, TooltipTrigger, createSecureClient, fromSupabaseClient, isSecureClient, scopeEqual, useAccessLevel, useCan, useEvents, useMultiplePermissions, usePermissions, useRBAC, useResolvedScope, useResourcePermissions, useRoleManagement, useSecureSupabase, warnIfInsecureClient };