@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
@@ -4,19 +4,62 @@
4
4
  * @module RBAC/Engine
5
5
  * @since 0.1.0
6
6
  *
7
- * Basic tests for the RBACEngine class focusing on essential functionality.
7
+ * Comprehensive tests for the RBACEngine class focusing on essential functionality.
8
8
  */
9
9
 
10
- import { vi, describe, it, expect, beforeEach } from 'vitest';
10
+ import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
11
11
  import { RBACEngine } from './engine';
12
12
  import type { PermissionCheck, Permission, UUID, Scope } from './types';
13
+ import { rbacCache } from './cache';
14
+ import { emitAuditEvent } from './audit';
15
+ import { SecurityContext } from './security';
16
+
17
+ // Mock dependencies
18
+ vi.mock('./cache', () => ({
19
+ rbacCache: {
20
+ get: vi.fn(),
21
+ set: vi.fn(),
22
+ delete: vi.fn(),
23
+ },
24
+ RBACCache: {
25
+ generateKey: vi.fn((userId, permission, orgId, eventId, appId, pageId) =>
26
+ `cache:${userId}:${permission}:${orgId}:${eventId}:${appId}:${pageId || ''}`
27
+ ),
28
+ generateAccessLevelKey: vi.fn((userId, orgId, eventId, appId) =>
29
+ `access:${userId}:${orgId}:${eventId}:${appId || ''}`
30
+ ),
31
+ generatePermissionMapKey: vi.fn((userId, orgId, eventId, appId) =>
32
+ `permmap:${userId}:${orgId}:${eventId}:${appId || ''}`
33
+ ),
34
+ },
35
+ }));
36
+
37
+ vi.mock('./audit', () => ({
38
+ emitAuditEvent: vi.fn(),
39
+ }));
40
+
41
+ vi.mock('./cache-invalidation', () => ({
42
+ initializeCacheInvalidation: vi.fn(),
43
+ }));
44
+
45
+ vi.mock('./config', () => ({
46
+ getRBACLogger: vi.fn(() => ({
47
+ error: vi.fn(),
48
+ warn: vi.fn(),
49
+ })),
50
+ }));
51
+
52
+ vi.mock('./errors', () => ({
53
+ categorizeError: vi.fn((_error) => 'database_error'),
54
+ mapErrorCategoryToSecurityEventType: vi.fn((_category) => 'database_error'),
55
+ }));
13
56
 
14
57
  // Mock Supabase client
15
- const createMockSupabaseClient = () => ({
16
- from: vi.fn(() => ({
58
+ const createMockSupabaseClient = () => {
59
+ const mockFrom = vi.fn(() => ({
17
60
  select: vi.fn().mockReturnThis(),
18
61
  eq: vi.fn().mockReturnThis(),
19
- is: vi.fn().mockReturnThis(), // Fixed: use 'is' not 'is_'
62
+ is: vi.fn().mockReturnThis(),
20
63
  lte: vi.fn().mockReturnThis(),
21
64
  or: vi.fn().mockReturnThis(),
22
65
  limit: vi.fn().mockResolvedValue({
@@ -24,215 +67,1016 @@ const createMockSupabaseClient = () => ({
24
67
  error: null
25
68
  }),
26
69
  single: vi.fn().mockResolvedValue({ data: null, error: null }),
27
- data: null,
28
- error: null
29
- })),
30
- rpc: vi.fn().mockResolvedValue({ data: false, error: null })
31
- });
70
+ maybeSingle: vi.fn().mockResolvedValue({ data: null, error: null }),
71
+ }));
72
+
73
+ return {
74
+ from: mockFrom,
75
+ rpc: vi.fn().mockResolvedValue({ data: false, error: null }),
76
+ };
77
+ };
32
78
 
33
79
  describe('RBACEngine', () => {
34
80
  let engine: RBACEngine;
35
81
  let mockSupabase: any;
36
- const mockUserId = 'user-123' as UUID;
37
- const mockOrgId = 'org-456' as UUID;
38
- const baseScope: Scope = { organisationId: mockOrgId, appId: 'app-1' as UUID };
82
+ const mockUserId = '123e4567-e89b-12d3-a456-426614174000' as UUID;
83
+ const mockOrgId = '123e4567-e89b-12d3-a456-426614174001' as UUID;
84
+ const baseScope: Scope = { organisationId: mockOrgId, appId: '123e4567-e89b-12d3-a456-426614174002' as UUID };
85
+ const validSecurityContext: SecurityContext = {
86
+ userId: mockUserId,
87
+ organisationId: mockOrgId,
88
+ ipAddress: '192.168.1.1',
89
+ userAgent: 'Mozilla/5.0',
90
+ timestamp: new Date(),
91
+ };
39
92
 
40
93
  beforeEach(() => {
41
94
  vi.clearAllMocks();
42
95
  mockSupabase = createMockSupabaseClient();
43
96
  engine = new RBACEngine(mockSupabase);
97
+ vi.mocked(rbacCache.get).mockReturnValue(null);
44
98
  });
45
99
 
46
- describe('Permission Resolution', () => {
47
- it('resolves super admin permissions correctly', async () => {
48
- // Simplified test - just verify the engine doesn't crash and returns a boolean
49
- const permissionCheck: PermissionCheck = {
50
- userId: mockUserId,
51
- scope: baseScope,
52
- permission: 'read:users' as Permission
53
- };
100
+ afterEach(() => {
101
+ vi.clearAllMocks();
102
+ });
103
+
104
+ describe('isPermitted', () => {
105
+ describe('Security Context Validation', () => {
106
+ it('requires security context parameter', async () => {
107
+ const permissionCheck: PermissionCheck = {
108
+ userId: mockUserId,
109
+ scope: baseScope,
110
+ permission: 'read:users' as Permission,
111
+ };
112
+
113
+ // TypeScript will catch this, but we test runtime behavior
114
+ await expect(
115
+ engine.isPermitted(permissionCheck, validSecurityContext)
116
+ ).resolves.toBeDefined();
117
+ });
54
118
 
55
- const result = await engine.isPermitted(permissionCheck);
56
- expect(typeof result).toBe('boolean');
119
+ it('validates security context userId format', async () => {
120
+ const invalidContext: SecurityContext = {
121
+ ...validSecurityContext,
122
+ userId: 'invalid-uuid' as UUID,
123
+ };
124
+
125
+ const permissionCheck: PermissionCheck = {
126
+ userId: 'invalid-uuid' as UUID,
127
+ scope: baseScope,
128
+ permission: 'read:users' as Permission,
129
+ };
130
+
131
+ const result = await engine.isPermitted(permissionCheck, invalidContext);
132
+ expect(result).toBe(false);
133
+ });
134
+
135
+ it('validates permission format in security context', async () => {
136
+ const permissionCheck: PermissionCheck = {
137
+ userId: mockUserId,
138
+ scope: baseScope,
139
+ permission: 'invalid-permission' as Permission,
140
+ };
141
+
142
+ const result = await engine.isPermitted(permissionCheck, validSecurityContext);
143
+ expect(result).toBe(false);
144
+ });
145
+
146
+ it('validates scope format in security context', async () => {
147
+ const invalidScopeCheck: PermissionCheck = {
148
+ userId: mockUserId,
149
+ scope: {} as Scope,
150
+ permission: 'read:users' as Permission,
151
+ };
152
+
153
+ const result = await engine.isPermitted(invalidScopeCheck, validSecurityContext);
154
+ expect(result).toBe(false);
155
+ });
57
156
  });
58
157
 
59
- it('resolves organisation admin permissions correctly', async () => {
60
- // Simplified test - just verify the engine doesn't crash and returns a boolean
61
- const permissionCheck: PermissionCheck = {
62
- userId: mockUserId,
63
- scope: baseScope,
64
- permission: 'read:users' as Permission
158
+ describe('Rate Limiting', () => {
159
+ it('respects rate limits from security middleware', async () => {
160
+ // Mock rate limit exceeded
161
+ const permissionCheck: PermissionCheck = {
162
+ userId: mockUserId,
163
+ scope: baseScope,
164
+ permission: 'read:users' as Permission,
165
+ };
166
+
167
+ // The middleware will reject if rate limit is exceeded
168
+ // We can't easily test this without mocking the middleware, but we verify it's called
169
+ const result = await engine.isPermitted(permissionCheck, validSecurityContext);
170
+ expect(typeof result).toBe('boolean');
171
+ });
172
+ });
173
+
174
+ describe('Cache Behavior', () => {
175
+ it('returns cached result when cache hit', async () => {
176
+ vi.mocked(rbacCache.get).mockReturnValue(true);
177
+
178
+ const permissionCheck: PermissionCheck = {
179
+ userId: mockUserId,
180
+ scope: baseScope,
181
+ permission: 'read:users' as Permission,
182
+ };
183
+
184
+ const result = await engine.isPermitted(permissionCheck, validSecurityContext);
185
+ expect(result).toBe(true);
186
+ expect(mockSupabase.rpc).not.toHaveBeenCalled();
187
+ expect(emitAuditEvent).not.toHaveBeenCalled();
188
+ });
189
+
190
+ it('calls RPC when cache miss', async () => {
191
+ vi.mocked(rbacCache.get).mockReturnValue(null);
192
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
193
+
194
+ const permissionCheck: PermissionCheck = {
195
+ userId: mockUserId,
196
+ scope: baseScope,
197
+ permission: 'read:users' as Permission,
198
+ };
199
+
200
+ const result = await engine.isPermitted(permissionCheck, validSecurityContext);
201
+ expect(result).toBe(true);
202
+ expect(mockSupabase.rpc).toHaveBeenCalledWith(
203
+ 'rbac_check_permission_simplified',
204
+ expect.objectContaining({
205
+ p_user_id: mockUserId,
206
+ p_permission: 'read:users',
207
+ })
208
+ );
209
+ });
210
+
211
+ it('caches RPC result', async () => {
212
+ vi.mocked(rbacCache.get).mockReturnValue(null);
213
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
214
+
215
+ const permissionCheck: PermissionCheck = {
216
+ userId: mockUserId,
217
+ scope: baseScope,
218
+ permission: 'read:users' as Permission,
219
+ };
220
+
221
+ await engine.isPermitted(permissionCheck, validSecurityContext);
222
+ expect(rbacCache.set).toHaveBeenCalled();
223
+ });
224
+ });
225
+
226
+ describe('RPC Integration', () => {
227
+ it('calls RPC with correct parameters', async () => {
228
+ vi.mocked(rbacCache.get).mockReturnValue(null);
229
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
230
+
231
+ const permissionCheck: PermissionCheck = {
232
+ userId: mockUserId,
233
+ scope: { organisationId: mockOrgId, eventId: 'event-1', appId: baseScope.appId },
234
+ permission: 'read:users' as Permission,
235
+ pageId: 'page-123' as UUID,
236
+ };
237
+
238
+ await engine.isPermitted(permissionCheck, validSecurityContext);
239
+
240
+ expect(mockSupabase.rpc).toHaveBeenCalledWith(
241
+ 'rbac_check_permission_simplified',
242
+ {
243
+ p_user_id: mockUserId,
244
+ p_permission: 'read:users',
245
+ p_organisation_id: mockOrgId,
246
+ p_event_id: 'event-1',
247
+ p_app_id: baseScope.appId,
248
+ p_page_id: 'page-123',
249
+ }
250
+ );
251
+ });
252
+
253
+ it('handles RPC errors gracefully', async () => {
254
+ vi.mocked(rbacCache.get).mockReturnValue(null);
255
+ mockSupabase.rpc.mockResolvedValue({
256
+ data: null,
257
+ error: { message: 'Database error', code: 'PGRST116' },
258
+ });
259
+
260
+ const permissionCheck: PermissionCheck = {
261
+ userId: mockUserId,
262
+ scope: baseScope,
263
+ permission: 'read:users' as Permission,
264
+ };
265
+
266
+ const result = await engine.isPermitted(permissionCheck, validSecurityContext);
267
+ expect(result).toBe(false);
268
+ });
269
+
270
+ it('handles RPC exceptions gracefully', async () => {
271
+ vi.mocked(rbacCache.get).mockReturnValue(null);
272
+ mockSupabase.rpc.mockRejectedValue(new Error('Network error'));
273
+
274
+ const permissionCheck: PermissionCheck = {
275
+ userId: mockUserId,
276
+ scope: baseScope,
277
+ permission: 'read:users' as Permission,
278
+ };
279
+
280
+ const result = await engine.isPermitted(permissionCheck, validSecurityContext);
281
+ expect(result).toBe(false);
282
+ });
283
+ });
284
+
285
+ describe('Audit Logging', () => {
286
+ it('emits audit event when permission granted', async () => {
287
+ vi.mocked(rbacCache.get).mockReturnValue(null);
288
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
289
+
290
+ const permissionCheck: PermissionCheck = {
291
+ userId: mockUserId,
292
+ scope: baseScope,
293
+ permission: 'read:users' as Permission,
294
+ };
295
+
296
+ await engine.isPermitted(permissionCheck, validSecurityContext);
297
+
298
+ expect(emitAuditEvent).toHaveBeenCalledWith(
299
+ expect.objectContaining({
300
+ type: 'permission_check',
301
+ userId: mockUserId,
302
+ organisationId: mockOrgId,
303
+ permission: 'read:users',
304
+ decision: true,
305
+ source: 'api',
306
+ })
307
+ );
308
+ });
309
+
310
+ it('emits audit event when permission denied', async () => {
311
+ vi.mocked(rbacCache.get).mockReturnValue(null);
312
+ mockSupabase.rpc.mockResolvedValue({ data: false, error: null });
313
+
314
+ const permissionCheck: PermissionCheck = {
315
+ userId: mockUserId,
316
+ scope: baseScope,
317
+ permission: 'read:users' as Permission,
318
+ };
319
+
320
+ await engine.isPermitted(permissionCheck, validSecurityContext);
321
+
322
+ expect(emitAuditEvent).toHaveBeenCalledWith(
323
+ expect.objectContaining({
324
+ type: 'permission_denied',
325
+ userId: mockUserId,
326
+ organisationId: mockOrgId,
327
+ permission: 'read:users',
328
+ decision: false,
329
+ source: 'api',
330
+ })
331
+ );
332
+ });
333
+
334
+ it('skips audit logging for cache hits', async () => {
335
+ vi.mocked(rbacCache.get).mockReturnValue(true);
336
+
337
+ const permissionCheck: PermissionCheck = {
338
+ userId: mockUserId,
339
+ scope: baseScope,
340
+ permission: 'read:users' as Permission,
341
+ };
342
+
343
+ await engine.isPermitted(permissionCheck, validSecurityContext);
344
+ expect(emitAuditEvent).not.toHaveBeenCalled();
345
+ });
346
+
347
+ it('skips audit logging when no organisation context', async () => {
348
+ vi.mocked(rbacCache.get).mockReturnValue(null);
349
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
350
+
351
+ const permissionCheck: PermissionCheck = {
352
+ userId: mockUserId,
353
+ scope: { appId: baseScope.appId }, // No organisationId
354
+ permission: 'read:users' as Permission,
355
+ };
356
+
357
+ const contextWithoutOrg: SecurityContext = {
358
+ ...validSecurityContext,
359
+ organisationId: null,
360
+ };
361
+
362
+ await engine.isPermitted(permissionCheck, contextWithoutOrg);
363
+ expect(emitAuditEvent).not.toHaveBeenCalled();
364
+ });
365
+ });
366
+ });
367
+
368
+ describe('getAccessLevel', () => {
369
+ it('returns cached access level when available', async () => {
370
+ vi.mocked(rbacCache.get).mockImplementation((key: string) => {
371
+ if (key.startsWith('super_admin:')) {
372
+ return false; // Not super admin (cached)
373
+ }
374
+ if (key.startsWith('access:')) {
375
+ return 'admin'; // Cached access level
376
+ }
377
+ return null;
378
+ });
379
+
380
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
381
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
382
+
383
+ expect(accessLevel).toBe('admin');
384
+ expect(mockSupabase.from).not.toHaveBeenCalled();
385
+ });
386
+
387
+ it('checks super admin status first', async () => {
388
+ // Mock cache to return null for super admin check, then mock DB query
389
+ vi.mocked(rbacCache.get).mockImplementation((key: string) => {
390
+ if (key.startsWith('super_admin:')) {
391
+ return null; // Not cached
392
+ }
393
+ return null; // Not cached for access level either
394
+ });
395
+
396
+ // Mock the super admin database query
397
+ const mockQuery = {
398
+ select: vi.fn().mockReturnThis(),
399
+ eq: vi.fn().mockReturnThis(),
400
+ is: vi.fn().mockReturnThis(),
401
+ lte: vi.fn().mockReturnThis(),
402
+ or: vi.fn().mockReturnThis(),
403
+ limit: vi.fn().mockResolvedValue({
404
+ data: [{ role: 'super_admin' }],
405
+ error: null,
406
+ }),
65
407
  };
408
+ mockSupabase.from.mockReturnValue(mockQuery);
66
409
 
67
- const result = await engine.isPermitted(permissionCheck);
68
- expect(typeof result).toBe('boolean');
410
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
411
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
412
+
413
+ expect(accessLevel).toBe('super');
69
414
  });
70
415
 
71
- it('resolves event admin permissions correctly', async () => {
72
- // Simplified test - just verify the engine doesn't crash and returns a boolean
73
- const permissionCheck: PermissionCheck = {
74
- userId: mockUserId,
75
- scope: { organisationId: mockOrgId, eventId: 'event-1', appId: 'app-1' as UUID },
76
- permission: 'read:events' as Permission
416
+ it('defaults to viewer when no roles found', async () => {
417
+ vi.mocked(rbacCache.get).mockReturnValue(null);
418
+
419
+ // Mock the super admin database query to return empty
420
+ const mockQuery = {
421
+ select: vi.fn().mockReturnThis(),
422
+ eq: vi.fn().mockReturnThis(),
423
+ is: vi.fn().mockReturnThis(),
424
+ lte: vi.fn().mockReturnThis(),
425
+ or: vi.fn().mockReturnThis(),
426
+ limit: vi.fn().mockResolvedValue({
427
+ data: [],
428
+ error: null,
429
+ }),
77
430
  };
431
+ mockSupabase.from.mockReturnValue(mockQuery);
432
+
433
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
434
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
78
435
 
79
- const result = await engine.isPermitted(permissionCheck);
80
- expect(typeof result).toBe('boolean');
436
+ expect(accessLevel).toBe('viewer');
81
437
  });
438
+ });
82
439
 
83
- it('denies permissions for insufficient roles', async () => {
84
- const permissionCheck: PermissionCheck = {
85
- userId: mockUserId,
86
- scope: baseScope,
87
- permission: 'delete:users' as Permission
440
+ describe('getPermissionMap', () => {
441
+ it('returns cached permission map when available', async () => {
442
+ const cachedMap = { 'read:page.meals': true };
443
+ vi.mocked(rbacCache.get)
444
+ .mockReturnValueOnce(null) // For super admin cache check
445
+ .mockReturnValueOnce(cachedMap); // For permission map cache
446
+
447
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
448
+ const permissionMap = await engine.getPermissionMap({ userId: mockUserId, scope });
449
+
450
+ expect(permissionMap).toEqual(cachedMap);
451
+ });
452
+
453
+ it('returns wildcard map for super admins', async () => {
454
+ vi.mocked(rbacCache.get).mockImplementation((key: string) => {
455
+ if (key.startsWith('super_admin:')) {
456
+ return null; // Not cached
457
+ }
458
+ return null; // Not cached for permission map either
459
+ });
460
+
461
+ // Mock the super admin database query
462
+ const mockQuery = {
463
+ select: vi.fn().mockReturnThis(),
464
+ eq: vi.fn().mockReturnThis(),
465
+ is: vi.fn().mockReturnThis(),
466
+ lte: vi.fn().mockReturnThis(),
467
+ or: vi.fn().mockReturnThis(),
468
+ limit: vi.fn().mockResolvedValue({
469
+ data: [{ role: 'super_admin' }],
470
+ error: null,
471
+ }),
88
472
  };
473
+ mockSupabase.from.mockReturnValue(mockQuery);
89
474
 
90
- const result = await engine.isPermitted(permissionCheck);
91
- expect(result).toBe(false);
475
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
476
+ const permissionMap = await engine.getPermissionMap({ userId: mockUserId, scope });
477
+
478
+ expect(permissionMap).toEqual({ '*': true });
92
479
  });
93
480
 
94
- it('handles database errors gracefully', async () => {
95
- mockSupabase.rpc.mockRejectedValue(new Error('Database connection failed'));
481
+ it('returns empty map when no organisation context', async () => {
482
+ vi.mocked(rbacCache.get).mockReturnValue(null);
96
483
 
97
- const permissionCheck: PermissionCheck = {
98
- userId: mockUserId,
99
- scope: baseScope,
100
- permission: 'read:users' as Permission
484
+ // Mock the super admin database query to return empty
485
+ const mockQuery = {
486
+ select: vi.fn().mockReturnThis(),
487
+ eq: vi.fn().mockReturnThis(),
488
+ is: vi.fn().mockReturnThis(),
489
+ lte: vi.fn().mockReturnThis(),
490
+ or: vi.fn().mockReturnThis(),
491
+ limit: vi.fn().mockResolvedValue({
492
+ data: [],
493
+ error: null,
494
+ }),
101
495
  };
496
+ mockSupabase.from.mockReturnValue(mockQuery);
102
497
 
103
- const result = await engine.isPermitted(permissionCheck);
104
- expect(result).toBe(false);
498
+ const scope: Scope = { appId: baseScope.appId }; // No organisationId
499
+ const permissionMap = await engine.getPermissionMap({ userId: mockUserId, scope });
500
+
501
+ expect(permissionMap).toEqual({});
105
502
  });
106
503
  });
107
504
 
108
- describe('Role Hierarchy', () => {
109
- it('respects global role hierarchy', async () => {
110
- // Simplified test - just verify the engine doesn't crash and returns a boolean
111
- const superAdminCheck: PermissionCheck = {
505
+ describe('resolveAppContext', () => {
506
+ it('resolves app context successfully', async () => {
507
+ mockSupabase.rpc.mockResolvedValue({
508
+ data: [{ app_id: baseScope.appId, has_access: true }],
509
+ error: null,
510
+ });
511
+
512
+ const context = await engine.resolveAppContext({
112
513
  userId: mockUserId,
113
- scope: baseScope,
114
- permission: 'read:users' as Permission
115
- };
514
+ appName: 'test-app',
515
+ });
116
516
 
117
- const result = await engine.isPermitted(superAdminCheck);
118
- expect(typeof result).toBe('boolean');
517
+ expect(context).toEqual({
518
+ appId: baseScope.appId,
519
+ hasAccess: true,
520
+ });
119
521
  });
120
522
 
121
- it('respects organisation role hierarchy', async () => {
122
- // Simplified test - just verify the engine doesn't crash and returns a boolean
123
- const orgAdminCheck: PermissionCheck = {
523
+ it('returns null when app not found', async () => {
524
+ mockSupabase.rpc.mockResolvedValue({
525
+ data: [],
526
+ error: null,
527
+ });
528
+
529
+ const context = await engine.resolveAppContext({
124
530
  userId: mockUserId,
125
- scope: baseScope,
126
- permission: 'read:users' as Permission
127
- };
531
+ appName: 'nonexistent-app',
532
+ });
128
533
 
129
- const result = await engine.isPermitted(orgAdminCheck);
130
- expect(typeof result).toBe('boolean');
534
+ expect(context).toBeNull();
535
+ });
536
+
537
+ it('handles RPC errors gracefully', async () => {
538
+ mockSupabase.rpc.mockResolvedValue({
539
+ data: null,
540
+ error: { message: 'Database error' },
541
+ });
542
+
543
+ const context = await engine.resolveAppContext({
544
+ userId: mockUserId,
545
+ appName: 'test-app',
546
+ });
547
+
548
+ expect(context).toBeNull();
131
549
  });
132
550
  });
133
551
 
134
- describe('Access Level Resolution', () => {
135
- it('resolves super admin access level', async () => {
136
- const scope: Scope = { organisationId: mockOrgId, appId: 'app-1' as UUID };
137
- const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
138
-
139
- expect(typeof accessLevel).toBe('string');
552
+ describe('getRoleContext', () => {
553
+ it('returns role context successfully', async () => {
554
+ mockSupabase.rpc.mockResolvedValue({
555
+ data: [
556
+ { permission_type: 'all_permissions', role_name: 'super_admin' },
557
+ { permission_type: 'organisation_access', role_name: 'org_admin' },
558
+ ],
559
+ error: null,
560
+ });
561
+
562
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
563
+ const roleContext = await engine.getRoleContext({ userId: mockUserId, scope });
564
+
565
+ expect(roleContext).toEqual({
566
+ globalRole: 'super_admin',
567
+ organisationRole: 'org_admin',
568
+ eventAppRole: null,
569
+ });
140
570
  });
141
571
 
142
- it('resolves organisation admin access level', async () => {
143
- const scope: Scope = { organisationId: mockOrgId, appId: 'app-1' as UUID };
572
+ it('returns empty context on error', async () => {
573
+ mockSupabase.rpc.mockResolvedValue({
574
+ data: null,
575
+ error: { message: 'Database error' },
576
+ });
577
+
578
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
579
+ const roleContext = await engine.getRoleContext({ userId: mockUserId, scope });
580
+
581
+ expect(roleContext).toEqual({
582
+ globalRole: null,
583
+ organisationRole: null,
584
+ eventAppRole: null,
585
+ });
586
+ });
587
+
588
+ it('handles non-array data', async () => {
589
+ mockSupabase.rpc.mockResolvedValue({
590
+ data: null,
591
+ error: null,
592
+ });
593
+
594
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
595
+ const roleContext = await engine.getRoleContext({ userId: mockUserId, scope });
596
+
597
+ expect(roleContext).toEqual({
598
+ globalRole: null,
599
+ organisationRole: null,
600
+ eventAppRole: null,
601
+ });
602
+ });
603
+
604
+ it('maps event app roles correctly', async () => {
605
+ mockSupabase.rpc.mockResolvedValue({
606
+ data: [
607
+ { permission_type: 'event_app_access', role_name: 'viewer' },
608
+ { permission_type: 'event_app_access', role_name: 'participant' },
609
+ { permission_type: 'event_app_access', role_name: 'planner' },
610
+ { permission_type: 'event_app_access', role_name: 'admin' },
611
+ ],
612
+ error: null,
613
+ });
614
+
615
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
616
+ const roleContext = await engine.getRoleContext({ userId: mockUserId, scope });
617
+
618
+ // Should use the last one (admin maps to event_admin)
619
+ expect(roleContext.eventAppRole).toBe('event_admin');
620
+ });
621
+
622
+ it('maps organisation roles correctly', async () => {
623
+ mockSupabase.rpc.mockResolvedValue({
624
+ data: [
625
+ { permission_type: 'organisation_access', role_name: 'supporter' },
626
+ { permission_type: 'organisation_access', role_name: 'member' },
627
+ { permission_type: 'organisation_access', role_name: 'leader' },
628
+ { permission_type: 'organisation_access', role_name: 'org_admin' },
629
+ ],
630
+ error: null,
631
+ });
632
+
633
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
634
+ const roleContext = await engine.getRoleContext({ userId: mockUserId, scope });
635
+
636
+ // Should use the last one
637
+ expect(roleContext.organisationRole).toBe('org_admin');
638
+ });
639
+
640
+ it('handles exceptions in getRoleContext', async () => {
641
+ mockSupabase.rpc.mockRejectedValue(new Error('Network error'));
642
+
643
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
644
+ const roleContext = await engine.getRoleContext({ userId: mockUserId, scope });
645
+
646
+ expect(roleContext).toEqual({
647
+ globalRole: null,
648
+ organisationRole: null,
649
+ eventAppRole: null,
650
+ });
651
+ });
652
+ });
653
+
654
+ describe('getAccessLevel - Organisation Roles', () => {
655
+ it('returns admin for org_admin role', async () => {
656
+ vi.mocked(rbacCache.get).mockImplementation((key: string) => {
657
+ if (key.startsWith('super_admin:')) {
658
+ return false; // Not super admin (cached) - this means checkSuperAdmin won't call from()
659
+ }
660
+ return null;
661
+ });
662
+
663
+ // Create a query builder that chains properly
664
+ // The engine uses .limit(1) which returns { data: Array, error }
665
+ // The engine calls: from('rbac_organisation_roles').select('role').eq(...).limit(1)
666
+ // which returns { data: [{ role: 'org_admin' }], error: null }
667
+ const createOrgQueryBuilder = () => {
668
+ const builder: any = {
669
+ select: vi.fn().mockReturnThis(),
670
+ eq: vi.fn().mockReturnThis(),
671
+ is: vi.fn().mockReturnThis(),
672
+ lte: vi.fn().mockReturnThis(),
673
+ or: vi.fn().mockReturnThis(),
674
+ limit: vi.fn().mockResolvedValue({
675
+ data: [{ role: 'org_admin' }],
676
+ error: null,
677
+ }),
678
+ };
679
+ return builder;
680
+ };
681
+
682
+ // Since checkSuperAdmin returns false from cache, it won't call from()
683
+ // So we only need to mock the org role query
684
+ mockSupabase.from.mockReturnValueOnce(createOrgQueryBuilder());
685
+
686
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
144
687
  const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
145
-
146
- expect(typeof accessLevel).toBe('string');
688
+
689
+ expect(accessLevel).toBe('admin');
147
690
  });
148
691
 
149
- it('defaults to viewer access level', async () => {
150
- const scope: Scope = { organisationId: mockOrgId, appId: 'app-1' as UUID };
692
+ it('returns viewer when no org role found', async () => {
693
+ vi.mocked(rbacCache.get).mockReturnValue(null);
694
+
695
+ const mockQuery = {
696
+ select: vi.fn().mockReturnThis(),
697
+ eq: vi.fn().mockReturnThis(),
698
+ is: vi.fn().mockReturnThis(),
699
+ lte: vi.fn().mockReturnThis(),
700
+ or: vi.fn().mockReturnThis(),
701
+ limit: vi.fn().mockResolvedValue({
702
+ data: [],
703
+ error: null,
704
+ }),
705
+ };
706
+ mockSupabase.from.mockReturnValue(mockQuery);
707
+
708
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
151
709
  const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
152
-
710
+
153
711
  expect(accessLevel).toBe('viewer');
154
712
  });
155
713
  });
156
714
 
157
- describe('Security Validation', () => {
158
- it('validates input parameters', async () => {
159
- const invalidCheck: PermissionCheck = {
160
- userId: '' as UUID,
161
- scope: baseScope,
162
- permission: 'read:users' as Permission
715
+ describe('getAccessLevel - Event App Roles', () => {
716
+ it('returns admin for event_admin role', async () => {
717
+ vi.mocked(rbacCache.get).mockReturnValue(null);
718
+
719
+ const mockSuperAdminQuery = {
720
+ select: vi.fn().mockReturnThis(),
721
+ eq: vi.fn().mockReturnThis(),
722
+ is: vi.fn().mockReturnThis(),
723
+ lte: vi.fn().mockReturnThis(),
724
+ or: vi.fn().mockReturnThis(),
725
+ limit: vi.fn().mockResolvedValue({
726
+ data: [],
727
+ error: null,
728
+ }),
163
729
  };
164
730
 
165
- const result = await engine.isPermitted(invalidCheck);
166
- expect(result).toBe(false);
731
+ const mockOrgQuery = {
732
+ select: vi.fn().mockReturnThis(),
733
+ eq: vi.fn().mockReturnThis(),
734
+ is: vi.fn().mockReturnThis(),
735
+ lte: vi.fn().mockReturnThis(),
736
+ or: vi.fn().mockReturnThis(),
737
+ limit: vi.fn().mockResolvedValue({
738
+ data: [],
739
+ error: null,
740
+ }),
741
+ };
742
+
743
+ const mockEventQuery = {
744
+ select: vi.fn().mockReturnThis(),
745
+ eq: vi.fn().mockReturnThis(),
746
+ lte: vi.fn().mockReturnThis(),
747
+ or: vi.fn().mockReturnThis(),
748
+ single: vi.fn().mockResolvedValue({
749
+ data: { role: 'event_admin' },
750
+ error: null,
751
+ }),
752
+ };
753
+
754
+ mockSupabase.from
755
+ .mockReturnValueOnce(mockSuperAdminQuery) // Super admin check
756
+ .mockReturnValueOnce(mockOrgQuery) // Org role check
757
+ .mockReturnValueOnce(mockEventQuery); // Event role check
758
+
759
+ const scope: Scope = {
760
+ organisationId: mockOrgId,
761
+ eventId: 'event-123',
762
+ appId: baseScope.appId
763
+ };
764
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
765
+
766
+ expect(accessLevel).toBe('admin');
167
767
  });
168
768
 
169
- it('validates scope requirements', async () => {
170
- const invalidScopeCheck: PermissionCheck = {
171
- userId: mockUserId,
172
- scope: {} as Scope,
173
- permission: 'read:users' as Permission
769
+ it('returns planner for planner role', async () => {
770
+ vi.mocked(rbacCache.get).mockReturnValue(null);
771
+
772
+ const mockSuperAdminQuery = {
773
+ select: vi.fn().mockReturnThis(),
774
+ eq: vi.fn().mockReturnThis(),
775
+ is: vi.fn().mockReturnThis(),
776
+ lte: vi.fn().mockReturnThis(),
777
+ or: vi.fn().mockReturnThis(),
778
+ limit: vi.fn().mockResolvedValue({
779
+ data: [],
780
+ error: null,
781
+ }),
782
+ };
783
+
784
+ const mockOrgQuery = {
785
+ select: vi.fn().mockReturnThis(),
786
+ eq: vi.fn().mockReturnThis(),
787
+ is: vi.fn().mockReturnThis(),
788
+ lte: vi.fn().mockReturnThis(),
789
+ or: vi.fn().mockReturnThis(),
790
+ limit: vi.fn().mockResolvedValue({
791
+ data: [],
792
+ error: null,
793
+ }),
174
794
  };
175
795
 
176
- const result = await engine.isPermitted(invalidScopeCheck);
177
- expect(result).toBe(false);
796
+ const mockEventQuery = {
797
+ select: vi.fn().mockReturnThis(),
798
+ eq: vi.fn().mockReturnThis(),
799
+ lte: vi.fn().mockReturnThis(),
800
+ or: vi.fn().mockReturnThis(),
801
+ single: vi.fn().mockResolvedValue({
802
+ data: { role: 'planner' },
803
+ error: null,
804
+ }),
805
+ };
806
+
807
+ mockSupabase.from
808
+ .mockReturnValueOnce(mockSuperAdminQuery)
809
+ .mockReturnValueOnce(mockOrgQuery)
810
+ .mockReturnValueOnce(mockEventQuery);
811
+
812
+ const scope: Scope = {
813
+ organisationId: mockOrgId,
814
+ eventId: 'event-123',
815
+ appId: baseScope.appId
816
+ };
817
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
818
+
819
+ expect(accessLevel).toBe('planner');
178
820
  });
179
821
 
180
- it('validates permission format', async () => {
181
- const invalidPermissionCheck: PermissionCheck = {
182
- userId: mockUserId,
183
- scope: baseScope,
184
- permission: 'invalid-permission' as Permission
822
+ it('returns participant for participant role', async () => {
823
+ vi.mocked(rbacCache.get).mockReturnValue(null);
824
+
825
+ const mockSuperAdminQuery = {
826
+ select: vi.fn().mockReturnThis(),
827
+ eq: vi.fn().mockReturnThis(),
828
+ is: vi.fn().mockReturnThis(),
829
+ lte: vi.fn().mockReturnThis(),
830
+ or: vi.fn().mockReturnThis(),
831
+ limit: vi.fn().mockResolvedValue({
832
+ data: [],
833
+ error: null,
834
+ }),
835
+ };
836
+
837
+ const mockOrgQuery = {
838
+ select: vi.fn().mockReturnThis(),
839
+ eq: vi.fn().mockReturnThis(),
840
+ is: vi.fn().mockReturnThis(),
841
+ lte: vi.fn().mockReturnThis(),
842
+ or: vi.fn().mockReturnThis(),
843
+ limit: vi.fn().mockResolvedValue({
844
+ data: [],
845
+ error: null,
846
+ }),
847
+ };
848
+
849
+ const mockEventQuery = {
850
+ select: vi.fn().mockReturnThis(),
851
+ eq: vi.fn().mockReturnThis(),
852
+ lte: vi.fn().mockReturnThis(),
853
+ or: vi.fn().mockReturnThis(),
854
+ single: vi.fn().mockResolvedValue({
855
+ data: { role: 'participant' },
856
+ error: null,
857
+ }),
858
+ };
859
+
860
+ mockSupabase.from
861
+ .mockReturnValueOnce(mockSuperAdminQuery)
862
+ .mockReturnValueOnce(mockOrgQuery)
863
+ .mockReturnValueOnce(mockEventQuery);
864
+
865
+ const scope: Scope = {
866
+ organisationId: mockOrgId,
867
+ eventId: 'event-123',
868
+ appId: baseScope.appId
869
+ };
870
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
871
+
872
+ expect(accessLevel).toBe('participant');
873
+ });
874
+ });
875
+
876
+ describe('getPermissionMap - Edge Cases', () => {
877
+ it('handles empty pages array', async () => {
878
+ vi.mocked(rbacCache.get).mockReturnValue(null);
879
+
880
+ const mockSuperAdminQuery = {
881
+ select: vi.fn().mockReturnThis(),
882
+ eq: vi.fn().mockReturnThis(),
883
+ is: vi.fn().mockReturnThis(),
884
+ lte: vi.fn().mockReturnThis(),
885
+ or: vi.fn().mockReturnThis(),
886
+ limit: vi.fn().mockResolvedValue({
887
+ data: [],
888
+ error: null,
889
+ }),
890
+ };
891
+
892
+ const mockPagesQuery = {
893
+ select: vi.fn().mockReturnThis(),
894
+ eq: vi.fn().mockResolvedValue({
895
+ data: [],
896
+ error: null,
897
+ }),
898
+ };
899
+
900
+ mockSupabase.from
901
+ .mockReturnValueOnce(mockSuperAdminQuery)
902
+ .mockReturnValueOnce(mockPagesQuery);
903
+
904
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
905
+ const permissionMap = await engine.getPermissionMap({ userId: mockUserId, scope });
906
+
907
+ expect(permissionMap).toEqual({});
908
+ });
909
+
910
+ it('handles null pages data', async () => {
911
+ vi.mocked(rbacCache.get).mockReturnValue(null);
912
+
913
+ const mockSuperAdminQuery = {
914
+ select: vi.fn().mockReturnThis(),
915
+ eq: vi.fn().mockReturnThis(),
916
+ is: vi.fn().mockReturnThis(),
917
+ lte: vi.fn().mockReturnThis(),
918
+ or: vi.fn().mockReturnThis(),
919
+ limit: vi.fn().mockResolvedValue({
920
+ data: [],
921
+ error: null,
922
+ }),
185
923
  };
186
924
 
187
- const result = await engine.isPermitted(invalidPermissionCheck);
188
- expect(result).toBe(false);
925
+ const mockPagesQuery = {
926
+ select: vi.fn().mockReturnThis(),
927
+ eq: vi.fn().mockResolvedValue({
928
+ data: null,
929
+ error: null,
930
+ }),
931
+ };
932
+
933
+ mockSupabase.from
934
+ .mockReturnValueOnce(mockSuperAdminQuery)
935
+ .mockReturnValueOnce(mockPagesQuery);
936
+
937
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
938
+ const permissionMap = await engine.getPermissionMap({ userId: mockUserId, scope });
939
+
940
+ expect(permissionMap).toEqual({});
189
941
  });
190
942
  });
191
943
 
192
- describe('Error Handling', () => {
193
- it('handles database connection errors', async () => {
194
- mockSupabase.rpc.mockRejectedValue(new Error('Connection failed'));
944
+ describe('isPermitted - resolvePageId', () => {
945
+ it('resolves page name to UUID for audit logging', async () => {
946
+ vi.mocked(rbacCache.get).mockReturnValue(null);
947
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
948
+
949
+ const mockPageQuery = {
950
+ select: vi.fn().mockReturnThis(),
951
+ eq: vi.fn().mockReturnThis(),
952
+ maybeSingle: vi.fn().mockResolvedValue({
953
+ data: { id: '123e4567-e89b-12d3-a456-426614174000' },
954
+ error: null,
955
+ }),
956
+ };
957
+
958
+ mockSupabase.from.mockReturnValue(mockPageQuery);
195
959
 
196
960
  const permissionCheck: PermissionCheck = {
197
961
  userId: mockUserId,
198
962
  scope: baseScope,
199
- permission: 'read:users' as Permission
963
+ permission: 'read:users' as Permission,
964
+ pageId: 'test-page-name',
200
965
  };
201
966
 
202
- const result = await engine.isPermitted(permissionCheck);
203
- expect(result).toBe(false);
967
+ await engine.isPermitted(permissionCheck, validSecurityContext);
968
+
969
+ expect(emitAuditEvent).toHaveBeenCalledWith(
970
+ expect.objectContaining({
971
+ pageId: '123e4567-e89b-12d3-a456-426614174000',
972
+ })
973
+ );
204
974
  });
205
975
 
206
- it('handles timeout errors gracefully', async () => {
207
- mockSupabase.rpc.mockRejectedValue(new Error('Timeout'));
976
+ it('handles page resolution errors gracefully', async () => {
977
+ vi.mocked(rbacCache.get).mockReturnValue(null);
978
+ mockSupabase.rpc.mockResolvedValue({ data: true, error: null });
979
+
980
+ const mockPageQuery = {
981
+ select: vi.fn().mockReturnThis(),
982
+ eq: vi.fn().mockReturnThis(),
983
+ maybeSingle: vi.fn().mockResolvedValue({
984
+ data: null,
985
+ error: { message: 'Page not found', code: 'PGRST116' },
986
+ }),
987
+ };
988
+
989
+ mockSupabase.from.mockReturnValue(mockPageQuery);
208
990
 
209
991
  const permissionCheck: PermissionCheck = {
210
992
  userId: mockUserId,
211
993
  scope: baseScope,
212
- permission: 'read:users' as Permission
994
+ permission: 'read:users' as Permission,
995
+ pageId: 'nonexistent-page',
213
996
  };
214
997
 
215
- const result = await engine.isPermitted(permissionCheck);
216
- expect(result).toBe(false);
998
+ // Should not throw, should use original pageId
999
+ await engine.isPermitted(permissionCheck, validSecurityContext);
1000
+
1001
+ expect(emitAuditEvent).toHaveBeenCalled();
217
1002
  });
218
1003
  });
219
1004
 
220
- describe('Performance', () => {
221
- it('handles concurrent permission checks', async () => {
222
- const permissionChecks = Array.from({ length: 5 }, (_, i) => ({
223
- userId: mockUserId,
224
- scope: baseScope,
225
- permission: `read:resource${i}` as Permission
226
- }));
1005
+ describe('checkSuperAdmin - Indirect Tests', () => {
1006
+ it('caches super admin status', async () => {
1007
+ vi.mocked(rbacCache.get).mockReturnValue(null);
227
1008
 
228
- const results = await Promise.all(
229
- permissionChecks.map(check => engine.isPermitted(check))
230
- );
1009
+ const mockQuery = {
1010
+ select: vi.fn().mockReturnThis(),
1011
+ eq: vi.fn().mockReturnThis(),
1012
+ is: vi.fn().mockReturnThis(),
1013
+ lte: vi.fn().mockReturnThis(),
1014
+ or: vi.fn().mockReturnThis(),
1015
+ limit: vi.fn().mockResolvedValue({
1016
+ data: [{ role: 'super_admin' }],
1017
+ error: null,
1018
+ }),
1019
+ };
1020
+ mockSupabase.from.mockReturnValue(mockQuery);
231
1021
 
232
- expect(results).toHaveLength(5);
233
- results.forEach(result => {
234
- expect(typeof result).toBe('boolean');
1022
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
1023
+
1024
+ // First call
1025
+ await engine.getAccessLevel({ userId: mockUserId, scope });
1026
+
1027
+ // Second call should use cache
1028
+ vi.mocked(rbacCache.get).mockImplementation((key: string) => {
1029
+ if (key.startsWith('super_admin:')) {
1030
+ return true;
1031
+ }
1032
+ return null;
235
1033
  });
1034
+
1035
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
1036
+ expect(accessLevel).toBe('super');
1037
+ expect(mockSupabase.from).toHaveBeenCalledTimes(1); // Only called once
1038
+ });
1039
+
1040
+ it('handles super admin check errors', async () => {
1041
+ vi.mocked(rbacCache.get).mockReturnValue(null);
1042
+
1043
+ const mockQuery = {
1044
+ select: vi.fn().mockReturnThis(),
1045
+ eq: vi.fn().mockReturnThis(),
1046
+ is: vi.fn().mockReturnThis(),
1047
+ lte: vi.fn().mockReturnThis(),
1048
+ or: vi.fn().mockReturnThis(),
1049
+ limit: vi.fn().mockRejectedValue(new Error('Database error')),
1050
+ };
1051
+ mockSupabase.from.mockReturnValue(mockQuery);
1052
+
1053
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
1054
+
1055
+ // Should handle error gracefully and return viewer
1056
+ await expect(engine.getAccessLevel({ userId: mockUserId, scope })).rejects.toThrow('Database error');
1057
+ });
1058
+
1059
+ it('handles slow super admin checks without throwing', async () => {
1060
+ vi.mocked(rbacCache.get).mockReturnValue(null);
1061
+
1062
+ const mockQuery = {
1063
+ select: vi.fn().mockReturnThis(),
1064
+ eq: vi.fn().mockReturnThis(),
1065
+ is: vi.fn().mockReturnThis(),
1066
+ lte: vi.fn().mockReturnThis(),
1067
+ or: vi.fn().mockReturnThis(),
1068
+ limit: vi.fn().mockResolvedValue({
1069
+ data: [],
1070
+ error: null,
1071
+ }),
1072
+ };
1073
+ mockSupabase.from.mockReturnValue(mockQuery);
1074
+
1075
+ const scope: Scope = { organisationId: mockOrgId, appId: baseScope.appId };
1076
+
1077
+ // Should complete without throwing
1078
+ const accessLevel = await engine.getAccessLevel({ userId: mockUserId, scope });
1079
+ expect(accessLevel).toBe('viewer');
236
1080
  });
237
1081
  });
238
1082
  });