@jmruthers/pace-core 0.6.9 → 0.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1182) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +74 -2
  5. package/audit-tool/audits/03-architecture.cjs +220 -20
  6. package/audit-tool/audits/04-code-quality.cjs +95 -3
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +214 -25
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +3 -26
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +120 -8
  19. package/cursor-rules/06-security-rbac.mdc +126 -2
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/DataTable-EFYP2QLE.js +16 -0
  24. package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
  25. package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
  26. package/dist/api-BZR2CYXL.js +5 -0
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/assets/app-icons/admin_favicon.svg +462 -0
  29. package/dist/assets/app-icons/base_favicon.svg +85 -0
  30. package/dist/assets/app-icons/cake_favicon.svg +68 -0
  31. package/dist/assets/app-icons/core_favicon.svg +256 -0
  32. package/dist/assets/app-icons/gear_favicon.svg +91 -0
  33. package/dist/assets/app-icons/medi_favicon.svg +92 -0
  34. package/dist/assets/app-icons/mint_favicon.svg +83 -0
  35. package/dist/assets/app-icons/pace_favicon.svg +49 -0
  36. package/dist/assets/app-icons/pump_favicon.svg +68 -0
  37. package/dist/assets/app-icons/seed_favicon.svg +91 -0
  38. package/dist/assets/app-icons/team_favicon.svg +67 -0
  39. package/dist/assets/app-icons/trac_favicon.svg +112 -0
  40. package/dist/assets/app-icons/trip_favicon.svg +102 -0
  41. package/dist/audit-HI2DHUVU.js +4 -0
  42. package/dist/auth-JvdRVaud.d.ts +49 -0
  43. package/dist/chunk-2DL2WSOE.js +327 -0
  44. package/dist/chunk-2OEVOGGR.js +9598 -0
  45. package/dist/chunk-44CNXN4P.js +15 -0
  46. package/dist/chunk-4R3T5ENU.js +2943 -0
  47. package/dist/chunk-7A6IMHH2.js +2321 -0
  48. package/dist/chunk-BTHN5MKC.js +121 -0
  49. package/dist/chunk-CU2BU2MQ.js +2 -0
  50. package/dist/chunk-D6BMFMQZ.js +200 -0
  51. package/dist/chunk-DDMPHZ3D.js +58 -0
  52. package/dist/chunk-ENLXB7GP.js +721 -0
  53. package/dist/chunk-J2KQK6DG.js +2159 -0
  54. package/dist/chunk-KJXRL3XE.js +6434 -0
  55. package/dist/chunk-L5LFKKLJ.js +61 -0
  56. package/dist/chunk-PCSHBLPB.js +811 -0
  57. package/dist/chunk-QRYSEPHB.js +429 -0
  58. package/dist/chunk-RMLY6KB5.js +187 -0
  59. package/dist/chunk-SACF5YSM.js +31 -0
  60. package/dist/chunk-UZNAFKGW.js +125 -0
  61. package/dist/chunk-V7FTM2LU.js +1080 -0
  62. package/dist/chunk-WY6Y7KC3.js +264 -0
  63. package/dist/chunk-XOJME5T7.js +407 -0
  64. package/dist/chunk-XPFVT3GN.js +492 -0
  65. package/dist/chunk-YFTFFJIV.js +529 -0
  66. package/dist/chunk-YYTWKVHO.js +1334 -0
  67. package/dist/components.d.ts +12 -89
  68. package/dist/components.js +23 -55
  69. package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
  70. package/dist/eslint-rules/index.cjs +3 -0
  71. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  72. package/dist/eslint-rules/rules/05-styling.cjs +507 -0
  73. package/dist/eslint-rules/rules/06-security-rbac.cjs +84 -0
  74. package/dist/event-BfCox3N2.d.ts +265 -0
  75. package/dist/file-reference-DU1hcawx.d.ts +164 -0
  76. package/dist/functions-DH45k8ec.d.ts +208 -0
  77. package/dist/hooks.d.ts +28 -14
  78. package/dist/hooks.js +90 -56
  79. package/dist/icons/index.d.ts +1 -0
  80. package/dist/icons/index.js +1 -0
  81. package/dist/index.d.ts +392 -155
  82. package/dist/index.js +337 -347
  83. package/dist/pagination-BW1mqywp.d.ts +201 -0
  84. package/dist/papaparseLoader-WG2UXQ22.js +7 -0
  85. package/dist/providers.d.ts +29 -14
  86. package/dist/providers.js +7 -5
  87. package/dist/rbac/eslint-rules.js +2 -2
  88. package/dist/rbac/index.d.ts +180 -351
  89. package/dist/rbac/index.js +13 -11
  90. package/dist/theming/runtime.d.ts +28 -5
  91. package/dist/theming/runtime.js +2 -2
  92. package/dist/timezone-BTWWXKVY.d.ts +696 -0
  93. package/dist/types-BE2sEHKd.d.ts +55 -0
  94. package/dist/types-CvOPXWWZ.d.ts +111 -0
  95. package/dist/types-Dr8sNhER.d.ts +50 -0
  96. package/dist/types.d.ts +20 -13
  97. package/dist/types.js +1 -0
  98. package/dist/usePublicPageContext-B91dGYW1.d.ts +4367 -0
  99. package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
  100. package/dist/utils.d.ts +338 -156
  101. package/dist/utils.js +78 -60
  102. package/dist/validation-g5n0hDkh.d.ts +177 -0
  103. package/docs/api/modules.md +1226 -1094
  104. package/docs/api-reference/components.md +5 -5
  105. package/docs/api-reference/rpc-functions.md +12 -3
  106. package/docs/core-concepts/rbac-system.md +8 -0
  107. package/docs/getting-started/cursor-rules.md +17 -20
  108. package/docs/getting-started/dependencies.md +1 -1
  109. package/docs/getting-started/setup.md +235 -0
  110. package/docs/implementation-guides/authentication.md +27 -0
  111. package/docs/implementation-guides/data-tables.md +365 -10
  112. package/docs/migration/ApiResult-migration.md +25 -0
  113. package/docs/rbac/RBAC_CONTRACT.md +0 -12
  114. package/docs/rbac/api-reference.md +33 -31
  115. package/docs/standards/0-standards-overview.md +50 -15
  116. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  117. package/docs/standards/2-project-structure-standards.md +45 -90
  118. package/docs/standards/3-architecture-standards.md +41 -1
  119. package/docs/standards/4-code-quality-standards.md +26 -6
  120. package/docs/standards/5-styling-standards.md +35 -1
  121. package/docs/standards/6-security-rbac-standards.md +288 -7
  122. package/docs/standards/7-api-tech-stack-standards.md +116 -17
  123. package/docs/standards/8-testing-documentation-standards.md +31 -0
  124. package/docs/standards/9-operations-standards.md +19 -0
  125. package/docs/standards/README.md +20 -201
  126. package/docs/testing/README.md +10 -0
  127. package/docs/testing/test-setup-for-consumers.md +916 -0
  128. package/docs/troubleshooting/common-issues.md +17 -1
  129. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  130. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  131. package/eslint-config-pace-core.cjs +24 -0
  132. package/package.json +14 -20
  133. package/scripts/build-docs.js +180 -0
  134. package/scripts/setup.cjs +536 -0
  135. package/scripts/validate.cjs +480 -0
  136. package/src/__mocks__/lucide-react.ts +0 -2
  137. package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
  138. package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
  139. package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
  140. package/src/__tests__/helpers/test-providers.test.tsx +99 -0
  141. package/src/__tests__/helpers/test-providers.tsx +37 -39
  142. package/src/__tests__/helpers/test-utils.test.tsx +447 -0
  143. package/src/__tests__/helpers/timer-utils.test.ts +371 -0
  144. package/src/assets/app-icons/admin_favicon.svg +462 -0
  145. package/src/assets/app-icons/base_favicon.svg +85 -0
  146. package/src/assets/app-icons/cake_favicon.svg +68 -0
  147. package/src/assets/app-icons/core_favicon.svg +256 -0
  148. package/src/assets/app-icons/gear_favicon.svg +91 -0
  149. package/src/assets/app-icons/index.test.ts +304 -0
  150. package/src/assets/app-icons/index.ts +83 -0
  151. package/src/assets/app-icons/medi_favicon.svg +92 -0
  152. package/src/assets/app-icons/mint_favicon.svg +83 -0
  153. package/src/assets/app-icons/pace_favicon.svg +49 -0
  154. package/src/assets/app-icons/pump_favicon.svg +68 -0
  155. package/src/assets/app-icons/seed_favicon.svg +91 -0
  156. package/src/assets/app-icons/team_favicon.svg +67 -0
  157. package/src/assets/app-icons/trac_favicon.svg +112 -0
  158. package/src/assets/app-icons/trip_favicon.svg +102 -0
  159. package/src/components/AddressField/AddressField.test.tsx +379 -4
  160. package/src/components/AddressField/AddressField.tsx +239 -213
  161. package/src/components/AddressField/types.ts +2 -2
  162. package/src/components/Alert/Alert.test.tsx +35 -25
  163. package/src/components/Alert/Alert.tsx +8 -8
  164. package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
  165. package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
  166. package/src/components/Avatar/Avatar.test.tsx +11 -1
  167. package/src/components/Avatar/Avatar.tsx +3 -2
  168. package/src/components/Badge/Badge.test.tsx +11 -1
  169. package/src/components/Button/Button.test.tsx +13 -3
  170. package/src/components/Button/Button.tsx +1 -1
  171. package/src/components/Calendar/Calendar.test.tsx +523 -131
  172. package/src/components/Calendar/Calendar.tsx +107 -488
  173. package/src/components/Card/Card.test.tsx +384 -258
  174. package/src/components/Card/Card.tsx +19 -10
  175. package/src/components/Checkbox/Checkbox.test.tsx +58 -174
  176. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  177. package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
  178. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  179. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  180. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  181. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  182. package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
  183. package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
  184. package/src/components/DataTable/DataTable.export.test.tsx +705 -0
  185. package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
  186. package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
  187. package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
  188. package/src/components/DataTable/DataTable.test.tsx +787 -416
  189. package/src/components/DataTable/DataTable.tsx +14 -14
  190. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  191. package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
  192. package/src/components/DataTable/DataTableCore.test.tsx +970 -0
  193. package/src/components/DataTable/README.md +155 -0
  194. package/src/components/DataTable/TESTING.md +101 -0
  195. package/src/components/DataTable/a11y.basic.test.tsx +788 -0
  196. package/src/components/DataTable/components/DataTableCore.tsx +126 -894
  197. package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
  198. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -3
  199. package/src/components/DataTable/components/ImportModal.tsx +82 -408
  200. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  201. package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
  202. package/src/components/DataTable/context/DataTableContext.tsx +13 -13
  203. package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
  204. package/src/components/DataTable/core/ColumnFactory.ts +3 -3
  205. package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
  206. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
  207. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
  208. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
  209. package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
  210. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +15 -3
  211. package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
  212. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  213. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  214. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  215. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  216. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  217. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  218. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  219. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  220. package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
  221. package/src/components/DataTable/hooks/useDataTablePermissions.ts +81 -260
  222. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  223. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  224. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  225. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  226. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  227. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  228. package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
  229. package/src/components/DataTable/hooks/useDataTableState.ts +161 -114
  230. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  231. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  232. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  233. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  234. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  235. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  236. package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
  237. package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
  238. package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
  239. package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
  240. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  241. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  242. package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
  243. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +311 -271
  244. package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
  245. package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
  246. package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
  247. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +27 -4
  248. package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
  249. package/src/components/DataTable/hooks/useTableColumns.ts +15 -39
  250. package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
  251. package/src/components/DataTable/hooks/useTableHandlers.ts +13 -22
  252. package/src/components/DataTable/index.ts +28 -5
  253. package/src/components/DataTable/keyboard.test.tsx +734 -0
  254. package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
  255. package/src/components/DataTable/pagination.modes.test.tsx +728 -0
  256. package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
  257. package/src/components/DataTable/styles.test.ts +379 -0
  258. package/src/components/DataTable/styles.ts +0 -1
  259. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  260. package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
  261. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  262. package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
  263. package/src/components/DataTable/test-utils.ts +94 -0
  264. package/src/components/DataTable/types/actions.ts +71 -0
  265. package/src/components/DataTable/types/base.ts +39 -0
  266. package/src/components/DataTable/types/columns.ts +125 -0
  267. package/src/components/DataTable/types/export.ts +32 -0
  268. package/src/components/DataTable/types/features.ts +81 -0
  269. package/src/components/DataTable/types/hierarchical.ts +44 -0
  270. package/src/components/DataTable/types/index.ts +43 -0
  271. package/src/components/DataTable/types/pagination.ts +85 -0
  272. package/src/components/DataTable/types/performance.ts +47 -0
  273. package/src/components/DataTable/types/props.ts +62 -0
  274. package/src/components/DataTable/types/rbac.ts +45 -0
  275. package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
  276. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  277. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
  278. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
  279. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  280. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  281. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  282. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  283. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  284. package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
  285. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  286. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  287. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  288. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  289. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  290. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  291. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  292. package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
  293. package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
  294. package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
  295. package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
  296. package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
  297. package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
  298. package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
  299. package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
  300. package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
  301. package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
  302. package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
  303. package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
  304. package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
  305. package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
  306. package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
  307. package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
  308. package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
  309. package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
  310. package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
  311. package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
  312. package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
  313. package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
  314. package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
  315. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  316. package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
  317. package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
  318. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
  319. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
  320. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
  321. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
  322. package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
  323. package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
  324. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  325. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  326. package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
  327. package/src/components/DataTable/utils/a11yUtils.ts +1 -1
  328. package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
  329. package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
  330. package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
  331. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  332. package/src/components/DataTable/utils/csvParse.ts +65 -0
  333. package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
  334. package/src/components/DataTable/utils/errorHandling.ts +3 -1
  335. package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
  336. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  337. package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
  338. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  339. package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
  340. package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
  341. package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
  342. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  343. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  344. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  345. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  346. package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
  347. package/src/components/DataTable/utils/paginationUtils.ts +7 -4
  348. package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
  349. package/src/components/DataTable/utils/performanceUtils.ts +1 -1
  350. package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
  351. package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
  352. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -67
  353. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +18 -25
  354. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
  355. package/src/components/DateTimeField/DateTimeField.test.tsx +3 -16
  356. package/src/components/DateTimeField/DateTimeField.tsx +1 -1
  357. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  358. package/src/components/Dialog/Dialog.test.tsx +2865 -458
  359. package/src/components/Dialog/Dialog.tsx +183 -986
  360. package/src/components/Dialog/dialogLock.test.ts +238 -0
  361. package/src/components/Dialog/dialogLock.ts +98 -0
  362. package/src/components/Dialog/index.ts +2 -0
  363. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  364. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  365. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  366. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  367. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  368. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  369. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
  370. package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
  371. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
  372. package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
  373. package/src/components/ErrorBoundary/index.ts +3 -4
  374. package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
  375. package/src/components/FileDisplay/FileDisplay.test.tsx +479 -247
  376. package/src/components/FileDisplay/FileDisplay.tsx +29 -659
  377. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  378. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  379. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  380. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  381. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  382. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  383. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  384. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  385. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  386. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  387. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  388. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  389. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  390. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  391. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  392. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  393. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  394. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  395. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  396. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  397. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  398. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  399. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  400. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  401. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  402. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  403. package/src/components/FileDisplay/index.tsx +1 -1
  404. package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
  405. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  406. package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1438 -0
  407. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  408. package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
  409. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  410. package/src/components/FileUpload/FileUpload.test.tsx +69 -27
  411. package/src/components/FileUpload/FileUpload.tsx +112 -527
  412. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  413. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  414. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  415. package/src/components/FileUpload/index.tsx +1 -1
  416. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  417. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  418. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  419. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  420. package/src/components/Footer/Footer.test.tsx +15 -382
  421. package/src/components/Footer/Footer.tsx +8 -125
  422. package/src/components/Form/Form.test.tsx +425 -88
  423. package/src/components/Form/Form.tsx +91 -299
  424. package/src/components/Form/useFormPersistence.ts +257 -0
  425. package/src/components/Header/Header.test.tsx +653 -163
  426. package/src/components/Header/Header.tsx +62 -44
  427. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
  428. package/src/components/Input/Input.test.tsx +34 -120
  429. package/src/components/Input/Input.tsx +1 -1
  430. package/src/components/Label/Label.test.tsx +46 -45
  431. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +8 -11
  432. package/src/components/LoginForm/LoginForm.test.tsx +0 -1
  433. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  434. package/src/components/NavigationMenu/NavigationMenu.test.tsx +2422 -102
  435. package/src/components/NavigationMenu/NavigationMenu.tsx +62 -362
  436. package/src/components/NavigationMenu/index.ts +6 -1
  437. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  438. package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
  439. package/src/components/NavigationMenu/useNavigationFiltering.ts +199 -308
  440. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  441. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1322 -0
  442. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +50 -49
  443. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
  444. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +103 -85
  445. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +774 -44
  446. package/src/components/PaceAppLayout/PaceAppLayout.tsx +282 -764
  447. package/src/components/PaceAppLayout/README.md +0 -9
  448. package/src/components/PaceAppLayout/test-setup.tsx +15 -9
  449. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  450. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  451. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  452. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  453. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  454. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  455. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  456. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +782 -20
  457. package/src/components/PaceLoginPage/PaceLoginPage.tsx +33 -125
  458. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  459. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
  460. package/src/components/Progress/Progress.test.tsx +127 -1
  461. package/src/components/Progress/Progress.tsx +1 -2
  462. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
  463. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -217
  464. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  465. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  466. package/src/components/PublicLayout/PublicLayout.test.tsx +1640 -38
  467. package/src/components/PublicLayout/PublicPageContext.ts +28 -0
  468. package/src/components/PublicLayout/PublicPageLayout.tsx +134 -75
  469. package/src/components/PublicLayout/PublicPageProvider.tsx +7 -42
  470. package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
  471. package/src/components/Select/Select.test.tsx +45 -8
  472. package/src/components/Select/Select.tsx +57 -40
  473. package/src/components/Select/context.test.tsx +56 -0
  474. package/src/components/Select/text.test.tsx +104 -0
  475. package/src/components/Select/text.ts +26 -0
  476. package/src/components/Select/types.ts +3 -0
  477. package/src/components/Select/useSelectEvents.test.ts +279 -0
  478. package/src/components/Select/useSelectEvents.ts +87 -0
  479. package/src/components/Select/useSelectSearch.test.tsx +295 -0
  480. package/src/components/Select/useSelectSearch.ts +91 -0
  481. package/src/components/Select/useSelectState.test.ts +268 -0
  482. package/src/components/Select/useSelectState.ts +104 -0
  483. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
  484. package/src/components/Switch/Switch.test.tsx +57 -153
  485. package/src/components/Table/Table.test.tsx +395 -317
  486. package/src/components/Tabs/Tabs.test.tsx +270 -0
  487. package/src/components/Tabs/Tabs.tsx +4 -4
  488. package/src/components/Textarea/Textarea.test.tsx +11 -38
  489. package/src/components/Toast/Toast.test.tsx +425 -496
  490. package/src/components/Tooltip/Tooltip.test.tsx +4 -21
  491. package/src/components/UserMenu/UserMenu.test.tsx +1 -21
  492. package/src/components/UserMenu/UserMenu.tsx +0 -1
  493. package/src/components/index.test.ts +346 -0
  494. package/src/components/index.ts +12 -1
  495. package/src/constants/performance.test.ts +91 -0
  496. package/src/hooks/ServiceHooks.test.tsx +725 -0
  497. package/src/hooks/hooks.integration.test.tsx +608 -0
  498. package/src/hooks/index.ts +18 -3
  499. package/src/hooks/index.unit.test.ts +220 -0
  500. package/src/hooks/public/usePublicEvent.test.ts +304 -0
  501. package/src/hooks/public/usePublicEvent.ts +11 -11
  502. package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
  503. package/src/hooks/public/usePublicEventLogo.ts +2 -2
  504. package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
  505. package/src/hooks/public/usePublicRouteParams.ts +2 -2
  506. package/src/hooks/services/useAuth.ts +9 -7
  507. package/src/hooks/services/useAuthService.ts +1 -1
  508. package/src/hooks/services/useEventService.ts +1 -1
  509. package/src/hooks/useAccessibleApps.test.ts +400 -0
  510. package/src/hooks/useAccessibleApps.ts +264 -0
  511. package/src/hooks/useAddressAutocomplete.test.ts +170 -47
  512. package/src/hooks/useAddressAutocomplete.ts +109 -81
  513. package/src/hooks/useApiFetch.unit.test.ts +111 -0
  514. package/src/hooks/useAppConfig.ts +13 -3
  515. package/src/hooks/useAppConfig.unit.test.ts +712 -0
  516. package/src/hooks/useComponentPerformance.unit.test.tsx +314 -0
  517. package/src/hooks/useDataTablePerformance.ts +111 -130
  518. package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
  519. package/src/hooks/useDataTableState.test.ts +170 -0
  520. package/src/hooks/useDataTableState.ts +5 -5
  521. package/src/hooks/useDebounce.unit.test.ts +157 -0
  522. package/src/hooks/useEventTheme.test.ts +70 -18
  523. package/src/hooks/useEventTheme.ts +50 -22
  524. package/src/hooks/useEvents.ts +49 -2
  525. package/src/hooks/useEvents.unit.test.ts +227 -0
  526. package/src/hooks/useFileReference.test.ts +388 -107
  527. package/src/hooks/useFileReference.ts +184 -179
  528. package/src/hooks/useFileUrl.ts +1 -1
  529. package/src/hooks/useFileUrl.unit.test.ts +686 -0
  530. package/src/hooks/useFileUrlCache.test.ts +319 -0
  531. package/src/hooks/useFileUrlCache.ts +5 -2
  532. package/src/hooks/useFocusManagement.unit.test.ts +604 -0
  533. package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
  534. package/src/hooks/useFormDialog.test.ts +307 -0
  535. package/src/hooks/useFormDialog.ts +2 -2
  536. package/src/hooks/useInactivityTracker.ts +141 -134
  537. package/src/hooks/useInactivityTracker.unit.test.ts +446 -0
  538. package/src/hooks/useIsMobile.unit.test.ts +317 -0
  539. package/src/hooks/useIsPrint.ts +62 -0
  540. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  541. package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
  542. package/src/hooks/useOrganisationPermissions.test.ts +1 -2
  543. package/src/hooks/useOrganisationPermissions.ts +1 -4
  544. package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
  545. package/src/hooks/useOrganisationSecurity.test.ts +4 -33
  546. package/src/hooks/useOrganisationSecurity.ts +192 -203
  547. package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
  548. package/src/hooks/useOrganisations.ts +1 -1
  549. package/src/hooks/useOrganisations.unit.test.ts +369 -0
  550. package/src/hooks/usePerformanceMonitor.ts +1 -1
  551. package/src/hooks/usePerformanceMonitor.unit.test.ts +693 -0
  552. package/src/hooks/usePermissionCache.test.ts +298 -329
  553. package/src/hooks/usePermissionCache.ts +277 -276
  554. package/src/hooks/usePreventTabReload.test.ts +307 -0
  555. package/src/hooks/usePublicEvent.simple.test.ts +794 -0
  556. package/src/hooks/usePublicEvent.test.ts +670 -0
  557. package/src/hooks/usePublicEvent.unit.test.ts +638 -0
  558. package/src/hooks/usePublicFileDisplay.test.ts +948 -0
  559. package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
  560. package/src/hooks/useQueryCache.test.ts +391 -0
  561. package/src/hooks/useQueryCache.ts +7 -9
  562. package/src/hooks/useRBAC.unit.test.ts +253 -0
  563. package/src/hooks/useSessionDraft.test.ts +556 -0
  564. package/src/hooks/useSessionDraft.ts +14 -11
  565. package/src/hooks/useSessionRestoration.ts +1 -1
  566. package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
  567. package/src/hooks/useStorage.ts +94 -54
  568. package/src/hooks/useStorage.unit.test.ts +684 -0
  569. package/src/hooks/useToast.test.ts +413 -0
  570. package/src/hooks/useToast.ts +2 -2
  571. package/src/hooks/useToast.unit.test.tsx +481 -0
  572. package/src/hooks/useZodForm.ts +3 -3
  573. package/src/hooks/useZodForm.unit.test.tsx +191 -0
  574. package/src/icons/index.test.ts +133 -0
  575. package/src/icons/index.ts +3 -1
  576. package/src/index.test.ts +528 -0
  577. package/src/index.ts +56 -9
  578. package/src/providers/AuthProvider.test.tsx +218 -0
  579. package/src/providers/EventProvider.test.tsx +487 -0
  580. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  581. package/src/providers/InactivityProvider.test.tsx +421 -0
  582. package/src/providers/ProviderLifecycle.test.tsx +308 -0
  583. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
  584. package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
  585. package/src/providers/index.test.ts +138 -0
  586. package/src/providers/services/AuthServiceContext.ts +27 -0
  587. package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
  588. package/src/providers/services/AuthServiceProvider.test.tsx +638 -0
  589. package/src/providers/services/AuthServiceProvider.tsx +81 -20
  590. package/src/providers/services/EventServiceContext.ts +25 -0
  591. package/src/providers/services/EventServiceProvider.test.tsx +839 -0
  592. package/src/providers/services/EventServiceProvider.tsx +11 -20
  593. package/src/providers/services/InactivityServiceContext.ts +25 -0
  594. package/src/providers/services/InactivityServiceProvider.test.tsx +662 -0
  595. package/src/providers/services/InactivityServiceProvider.tsx +7 -17
  596. package/src/providers/services/OrganisationServiceContext.ts +25 -0
  597. package/src/providers/services/OrganisationServiceProvider.test.tsx +440 -0
  598. package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
  599. package/src/providers/services/UnifiedAuthContext.ts +102 -0
  600. package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
  601. package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
  602. package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
  603. package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
  604. package/src/providers/services/UnifiedAuthProvider.tsx +147 -497
  605. package/src/providers/services/contexts.test.tsx +281 -0
  606. package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
  607. package/src/providers/services/useUnifiedAuth.ts +29 -0
  608. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  609. package/src/providers/useInactivity.test-helper.ts +27 -0
  610. package/src/rbac/README.md +5 -5
  611. package/src/rbac/adapters.comprehensive.test.tsx +429 -0
  612. package/src/rbac/adapters.test.tsx +654 -0
  613. package/src/rbac/adapters.tsx +53 -38
  614. package/src/rbac/api.test.ts +986 -259
  615. package/src/rbac/api.ts +260 -216
  616. package/src/rbac/audit-batched.test.ts +550 -0
  617. package/src/rbac/audit-batched.ts +5 -4
  618. package/src/rbac/audit.test.ts +225 -28
  619. package/src/rbac/audit.ts +26 -18
  620. package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
  621. package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
  622. package/src/rbac/cache-invalidation.test.ts +715 -0
  623. package/src/rbac/cache-invalidation.ts +18 -15
  624. package/src/rbac/cache.test.ts +123 -63
  625. package/src/rbac/cache.ts +3 -4
  626. package/src/rbac/components/AccessDenied.test.tsx +324 -0
  627. package/src/rbac/components/AccessDenied.tsx +20 -18
  628. package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
  629. package/src/rbac/components/NavigationGuard.tsx +10 -8
  630. package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
  631. package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
  632. package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
  633. package/src/rbac/components/PagePermissionGuard.test.tsx +1430 -0
  634. package/src/rbac/components/PagePermissionGuard.tsx +188 -381
  635. package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
  636. package/src/rbac/config.test.ts +131 -48
  637. package/src/rbac/config.ts +69 -26
  638. package/src/rbac/docs/event-based-apps.md +26 -13
  639. package/src/rbac/engine.comprehensive.test.ts +808 -0
  640. package/src/rbac/engine.test.ts +974 -130
  641. package/src/rbac/engine.ts +53 -13
  642. package/src/rbac/errors.test.ts +99 -87
  643. package/src/rbac/errors.ts +89 -55
  644. package/src/rbac/eslint-rules.js +2 -2
  645. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  646. package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
  647. package/src/rbac/hooks/permissions/useAccessLevel.ts +23 -14
  648. package/src/rbac/hooks/permissions/useCan.test.ts +798 -0
  649. package/src/rbac/hooks/permissions/useCan.ts +173 -253
  650. package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
  651. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +63 -10
  652. package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
  653. package/src/rbac/hooks/permissions/usePermissions.ts +50 -78
  654. package/src/rbac/hooks/useCan.test.ts +348 -32
  655. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  656. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  657. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  658. package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
  659. package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
  660. package/src/rbac/hooks/usePermissions.test.ts +459 -33
  661. package/src/rbac/hooks/usePermissions.ts +5 -7
  662. package/src/rbac/hooks/useRBAC.test.ts +1784 -21
  663. package/src/rbac/hooks/useRBAC.ts +148 -88
  664. package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
  665. package/src/rbac/hooks/useResolvedScope.ts +4 -1
  666. package/src/rbac/hooks/useResourcePermissions.test.ts +561 -24
  667. package/src/rbac/hooks/useResourcePermissions.ts +76 -140
  668. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  669. package/src/rbac/hooks/useRoleManagement.test.ts +634 -61
  670. package/src/rbac/hooks/useRoleManagement.ts +158 -586
  671. package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
  672. package/src/rbac/hooks/useSecureSupabase.ts +21 -14
  673. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  674. package/src/rbac/index.test.ts +107 -0
  675. package/src/rbac/index.ts +32 -32
  676. package/src/rbac/performance.test.ts +451 -0
  677. package/src/rbac/permissions.test.ts +149 -68
  678. package/src/rbac/permissions.ts +0 -3
  679. package/src/rbac/rbac-core.test.tsx +276 -0
  680. package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
  681. package/src/rbac/rbac-engine-simplified.test.ts +252 -0
  682. package/src/rbac/rbac-functions.test.ts +703 -0
  683. package/src/rbac/rbac-integration.test.ts +523 -0
  684. package/src/rbac/rbac-role-isolation.test.ts +456 -0
  685. package/src/rbac/request-deduplication.test.ts +352 -0
  686. package/src/rbac/request-deduplication.ts +5 -4
  687. package/src/rbac/scenarios.user-role.test.tsx +271 -0
  688. package/src/rbac/secureClient.test.ts +499 -115
  689. package/src/rbac/secureClient.ts +54 -28
  690. package/src/rbac/security.test.ts +448 -44
  691. package/src/rbac/security.ts +7 -6
  692. package/src/rbac/types/roleManagement.ts +66 -0
  693. package/src/rbac/types.test.ts +236 -0
  694. package/src/rbac/types.ts +7 -5
  695. package/src/rbac/utils/clientSecurity.test.ts +192 -0
  696. package/src/rbac/utils/clientSecurity.ts +6 -4
  697. package/src/rbac/utils/contextValidator.test.ts +126 -0
  698. package/src/rbac/utils/contextValidator.ts +6 -3
  699. package/src/rbac/utils/deep-equal.test.ts +76 -0
  700. package/src/rbac/utils/eventContext.test.ts +401 -0
  701. package/src/rbac/utils/eventContext.ts +38 -34
  702. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  703. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  704. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  705. package/src/services/AuthService.edge-cases.test.ts +746 -0
  706. package/src/services/AuthService.restoreSession.test.ts +59 -0
  707. package/src/services/AuthService.test.ts +1362 -0
  708. package/src/services/AuthService.ts +197 -216
  709. package/src/services/BaseService.edge-cases.test.ts +506 -0
  710. package/src/services/BaseService.test.ts +363 -0
  711. package/src/services/EventService.edge-cases.test.ts +636 -0
  712. package/src/services/EventService.eventColours.test.ts +64 -0
  713. package/src/services/EventService.test.ts +1250 -0
  714. package/src/services/EventService.ts +244 -315
  715. package/src/services/InactivityService.edge-cases.test.ts +492 -0
  716. package/src/services/InactivityService.lifecycle.test.ts +406 -0
  717. package/src/services/InactivityService.test.ts +829 -0
  718. package/src/services/InactivityService.ts +172 -213
  719. package/src/services/OrganisationService.edge-cases.test.ts +633 -0
  720. package/src/services/OrganisationService.pagination.test.ts +409 -0
  721. package/src/services/OrganisationService.test.ts +1579 -0
  722. package/src/services/OrganisationService.ts +186 -257
  723. package/src/services/base/BaseService.test.ts +214 -0
  724. package/src/services/interfaces/IAuthService.test.ts +184 -0
  725. package/src/services/interfaces/IAuthService.ts +10 -9
  726. package/src/services/interfaces/IEventService.test.ts +176 -0
  727. package/src/services/interfaces/IInactivityService.test.ts +183 -0
  728. package/src/services/interfaces/IOrganisationService.test.ts +207 -0
  729. package/src/services/interfaces/IOrganisationService.ts +0 -1
  730. package/src/styles/core.css +244 -12
  731. package/src/theming/parseEventColours.test.ts +321 -0
  732. package/src/theming/parseEventColours.ts +18 -9
  733. package/src/theming/runtime.test.ts +495 -0
  734. package/src/theming/runtime.ts +72 -7
  735. package/src/types/api-result.ts +53 -0
  736. package/src/types/auth.ts +0 -1
  737. package/src/types/core.test.ts +397 -0
  738. package/src/types/database-generated.test.ts +78 -0
  739. package/src/types/database.generated.ts +45 -10
  740. package/src/types/event.ts +39 -19
  741. package/src/types/file-reference.test.ts +351 -0
  742. package/src/types/file-reference.ts +37 -12
  743. package/src/types/guards.test.ts +246 -0
  744. package/src/types/index.test.ts +265 -0
  745. package/src/types/index.ts +3 -0
  746. package/src/types/organisation.roles.test.ts +55 -0
  747. package/src/types/organisation.test.ts +1105 -0
  748. package/src/types/organisation.ts +15 -15
  749. package/src/types/rpc-responses.ts +33 -0
  750. package/src/types/supabase.ts +14 -6
  751. package/src/types/theme.test.ts +830 -0
  752. package/src/types/type-validation.test.ts +526 -0
  753. package/src/types/validation.test.ts +729 -0
  754. package/src/types/vitest-globals.d.ts +1 -1
  755. package/src/utils/app/appConfig.test.ts +235 -0
  756. package/src/utils/app/appIdResolver.test.ts +252 -57
  757. package/src/utils/app/appIdResolver.ts +31 -20
  758. package/src/utils/app/appNameResolver.test.ts +18 -10
  759. package/src/utils/app/appNameResolver.ts +11 -9
  760. package/src/utils/app/appPortMap.test.ts +125 -0
  761. package/src/utils/app/appPortMap.ts +51 -0
  762. package/src/utils/app/buildAppUrl.test.ts +273 -0
  763. package/src/utils/app/buildAppUrl.ts +114 -0
  764. package/src/utils/appConfig.unit.test.ts +55 -0
  765. package/src/utils/audit/audit.test.ts +354 -39
  766. package/src/utils/audit.unit.test.ts +69 -0
  767. package/src/utils/auth-utils.unit.test.ts +69 -0
  768. package/src/utils/bundleAnalysis.unit.test.ts +326 -0
  769. package/src/utils/cn.unit.test.ts +34 -0
  770. package/src/utils/context/organisationContext.test.ts +115 -95
  771. package/src/utils/context/organisationContext.ts +32 -43
  772. package/src/utils/context/sessionTracking.test.ts +354 -0
  773. package/src/utils/core/cn.test.ts +66 -0
  774. package/src/utils/core/debugLogger.test.ts +113 -0
  775. package/src/utils/core/debugLogger.ts +15 -8
  776. package/src/utils/core/logger.test.ts +217 -0
  777. package/src/utils/core/logger.ts +20 -16
  778. package/src/utils/core/mergeRefs.ts +24 -0
  779. package/src/utils/debugLogger.test.ts +417 -0
  780. package/src/utils/device/deviceFingerprint.test.ts +8 -5
  781. package/src/utils/device/deviceFingerprint.ts +3 -3
  782. package/src/utils/deviceFingerprint.unit.test.ts +818 -0
  783. package/src/utils/dynamic/createLazyComponent.tsx +46 -0
  784. package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
  785. package/src/utils/dynamic/dynamicUtils.ts +6 -6
  786. package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
  787. package/src/utils/dynamic/lazyLoad.tsx +8 -36
  788. package/src/utils/dynamic/papaparseLoader.ts +7 -0
  789. package/src/utils/dynamicUtils.unit.test.ts +331 -0
  790. package/src/utils/file-reference/file-reference.test.ts +1238 -0
  791. package/src/utils/file-reference/index.ts +330 -348
  792. package/src/utils/formatDate.unit.test.ts +109 -0
  793. package/src/utils/formatting/formatDate.test.ts +22 -148
  794. package/src/utils/formatting/formatDateTime.test.ts +41 -119
  795. package/src/utils/formatting/formatDateTimeTimezone.test.ts +41 -85
  796. package/src/utils/formatting/formatNumber.test.ts +259 -0
  797. package/src/utils/formatting/formatTime.test.ts +36 -128
  798. package/src/utils/formatting/formatting.ts +1 -1
  799. package/src/utils/formatting.unit.test.ts +99 -0
  800. package/src/utils/google-places/googlePlacesUtils.test.ts +127 -36
  801. package/src/utils/google-places/googlePlacesUtils.ts +67 -86
  802. package/src/utils/google-places/loadGoogleMapsScript.test.ts +68 -8
  803. package/src/utils/google-places/loadGoogleMapsScript.ts +140 -118
  804. package/src/utils/index.ts +52 -11
  805. package/src/utils/index.unit.test.ts +251 -0
  806. package/src/utils/lazyLoad.unit.test.tsx +319 -0
  807. package/src/utils/location/location.test.ts +19 -116
  808. package/src/utils/logger.unit.test.ts +398 -0
  809. package/src/utils/organisationContext.unit.test.ts +180 -0
  810. package/src/utils/performance/bundleAnalysis.test.ts +148 -0
  811. package/src/utils/performance/bundleAnalysis.ts +16 -22
  812. package/src/utils/performance/performanceBenchmark.test.ts +251 -0
  813. package/src/utils/performance/performanceBenchmark.ts +12 -4
  814. package/src/utils/performance/performanceBudgets.test.ts +241 -0
  815. package/src/utils/performance/performanceBudgets.ts +9 -6
  816. package/src/utils/performanceBenchmark.test.ts +174 -0
  817. package/src/utils/performanceBudgets.unit.test.ts +288 -0
  818. package/src/utils/permissionTypes.unit.test.ts +250 -0
  819. package/src/utils/permissionUtils.unit.test.ts +362 -0
  820. package/src/utils/permissions/permissionTypes.test.ts +149 -0
  821. package/src/utils/permissions/permissionUtils.test.ts +20 -42
  822. package/src/utils/persistence/keyDerivation.test.ts +306 -0
  823. package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
  824. package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
  825. package/src/utils/request-deduplication.test.ts +349 -0
  826. package/src/utils/request-deduplication.ts +6 -4
  827. package/src/utils/sanitization.unit.test.ts +346 -0
  828. package/src/utils/schemaUtils.unit.test.ts +441 -0
  829. package/src/utils/secureDataAccess.unit.test.ts +334 -0
  830. package/src/utils/secureErrors.unit.test.ts +390 -0
  831. package/src/utils/secureStorage.unit.test.ts +289 -0
  832. package/src/utils/security/auth-utils.ts +38 -27
  833. package/src/utils/security/secureDataAccess.test.ts +22 -191
  834. package/src/utils/security/secureDataAccess.ts +241 -281
  835. package/src/utils/security/secureErrors.test.ts +163 -0
  836. package/src/utils/security/secureStorage.test.ts +156 -0
  837. package/src/utils/security/secureStorage.ts +1 -1
  838. package/src/utils/security/security.test.ts +212 -0
  839. package/src/utils/security/security.ts +15 -18
  840. package/src/utils/security/securityMonitor.test.ts +90 -0
  841. package/src/utils/security/securityMonitor.ts +1 -1
  842. package/src/utils/security.unit.test.ts +155 -0
  843. package/src/utils/securityMonitor.unit.test.ts +276 -0
  844. package/src/utils/sessionTracking.unit.test.ts +218 -0
  845. package/src/utils/storage/config.unit.test.ts +239 -0
  846. package/src/utils/storage/helpers.test.ts +769 -456
  847. package/src/utils/storage/helpers.ts +174 -253
  848. package/src/utils/storage/index.unit.test.ts +68 -0
  849. package/src/utils/storage/storageUtils.ts +32 -0
  850. package/src/utils/storage/types.ts +9 -2
  851. package/src/utils/supabase/createBaseClient.test.ts +201 -0
  852. package/src/utils/supabase/createBaseClient.ts +2 -1
  853. package/src/utils/timezone/timezone.test.ts +26 -44
  854. package/src/utils/timezone.test.ts +345 -0
  855. package/src/utils/validation/common.test.ts +115 -0
  856. package/src/utils/validation/csrf.test.ts +198 -0
  857. package/src/utils/validation/csrf.ts +42 -41
  858. package/src/utils/validation/htmlSanitization.ts +27 -31
  859. package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
  860. package/src/utils/validation/passwordSchema.test.ts +164 -0
  861. package/src/utils/validation/schema.test.ts +127 -0
  862. package/src/utils/validation/schema.ts +6 -3
  863. package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
  864. package/src/utils/validation/sqlInjectionProtection.ts +2 -2
  865. package/src/utils/validation/user.test.ts +173 -0
  866. package/src/utils/validation/validation.test.ts +197 -0
  867. package/src/utils/validation/validationUtils.test.ts +294 -0
  868. package/src/utils/validation.unit.test.ts +307 -0
  869. package/src/utils/validationUtils.unit.test.ts +558 -0
  870. package/src/vite-env.d.ts +6 -0
  871. package/dist/AuthService-DmfO5rGS.d.ts +0 -524
  872. package/dist/DataTable-DRUIgtUH.d.ts +0 -166
  873. package/dist/DataTable-SOAFXIWY.js +0 -15
  874. package/dist/PublicPageProvider-CIGSujI2.d.ts +0 -4147
  875. package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
  876. package/dist/UnifiedAuthProvider-CKvHP1MK.d.ts +0 -139
  877. package/dist/api-7P7DI652.js +0 -4
  878. package/dist/audit-MYQXYZFU.js +0 -3
  879. package/dist/auth-BZOJqrdd.d.ts +0 -49
  880. package/dist/chunk-4DDCYDQ3.js +0 -544
  881. package/dist/chunk-5HNSDQWH.js +0 -5046
  882. package/dist/chunk-5W2A3DRC.js +0 -164
  883. package/dist/chunk-6GLLNA6U.js +0 -31
  884. package/dist/chunk-7ILTDCL2.js +0 -80
  885. package/dist/chunk-A3W6LW53.js +0 -70
  886. package/dist/chunk-AHU7G2R5.js +0 -423
  887. package/dist/chunk-C7ZQ5O4C.js +0 -481
  888. package/dist/chunk-EF2UGZWY.js +0 -611
  889. package/dist/chunk-FEJLJNWA.js +0 -181
  890. package/dist/chunk-FYHN4DD5.js +0 -415
  891. package/dist/chunk-GS5672WG.js +0 -2003
  892. package/dist/chunk-HF6O3O37.js +0 -187
  893. package/dist/chunk-J2U36LHD.js +0 -8517
  894. package/dist/chunk-LX6U42O3.js +0 -2177
  895. package/dist/chunk-MPBLMWVR.js +0 -2161
  896. package/dist/chunk-OJ4SKRSV.js +0 -105
  897. package/dist/chunk-S6ZQKDY6.js +0 -62
  898. package/dist/chunk-S7DKJPLT.js +0 -699
  899. package/dist/chunk-T5CVK4R3.js +0 -2816
  900. package/dist/chunk-TTRFSOKR.js +0 -121
  901. package/dist/chunk-Z2FNRKF3.js +0 -994
  902. package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
  903. package/dist/event-CW5YB_2p.d.ts +0 -239
  904. package/dist/file-reference-BavO2eQj.d.ts +0 -148
  905. package/dist/functions-lBy5L2ry.d.ts +0 -208
  906. package/dist/timezone-0AyangqX.d.ts +0 -697
  907. package/dist/types-BeoeWV5I.d.ts +0 -110
  908. package/dist/types-DXstZpNI.d.ts +0 -614
  909. package/dist/types-t9H8qKRw.d.ts +0 -55
  910. package/dist/usePublicRouteParams-DQLrDqDb.d.ts +0 -876
  911. package/dist/useToast-AyaT-x7p.d.ts +0 -68
  912. package/dist/validation-643vUDZW.d.ts +0 -177
  913. package/scripts/build-docs-incremental.js +0 -179
  914. package/scripts/eslint-audit.cjs +0 -123
  915. package/scripts/generate-docs.js +0 -157
  916. package/scripts/install-cursor-rules.cjs +0 -255
  917. package/scripts/install-eslint-config.cjs +0 -349
  918. package/scripts/setup-build-cache.js +0 -73
  919. package/scripts/validate-pre-publish.js +0 -145
  920. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
  921. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
  922. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
  923. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
  924. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -448
  925. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
  926. package/src/__tests__/hooks/usePermissions.test.ts +0 -268
  927. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  928. package/src/__tests__/public-recipe-view.test.ts +0 -228
  929. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -220
  930. package/src/__tests__/rls-policies.test.ts +0 -471
  931. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
  932. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
  933. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
  934. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
  935. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
  936. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -483
  937. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  938. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
  939. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -1474
  940. package/src/components/DataTable/__tests__/README.md +0 -145
  941. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
  942. package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
  943. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
  944. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -730
  945. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -325
  946. package/src/components/DataTable/__tests__/styles.test.ts +0 -382
  947. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
  948. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -380
  949. package/src/components/DataTable/__tests__/test-utils.ts +0 -94
  950. package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
  951. package/src/components/DataTable/components/ActionButtons.tsx +0 -190
  952. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
  953. package/src/components/DataTable/components/ColumnFilter.tsx +0 -118
  954. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
  955. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
  956. package/src/components/DataTable/components/DataTableLayout.tsx +0 -573
  957. package/src/components/DataTable/components/DataTableModals.tsx +0 -245
  958. package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
  959. package/src/components/DataTable/components/EditFields.tsx +0 -327
  960. package/src/components/DataTable/components/EditableRow.tsx +0 -462
  961. package/src/components/DataTable/components/EmptyState.tsx +0 -79
  962. package/src/components/DataTable/components/FilterRow.tsx +0 -141
  963. package/src/components/DataTable/components/LoadingState.tsx +0 -17
  964. package/src/components/DataTable/components/PaginationControls.tsx +0 -289
  965. package/src/components/DataTable/components/RowComponent.tsx +0 -403
  966. package/src/components/DataTable/components/SortIndicator.tsx +0 -50
  967. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -355
  968. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -657
  969. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -913
  970. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -572
  971. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -612
  972. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -708
  973. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -479
  974. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -475
  975. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -157
  976. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -1061
  977. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -437
  978. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -474
  979. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -617
  980. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -1093
  981. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -139
  982. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -519
  983. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -1004
  984. package/src/components/DataTable/components/cellValueUtils.ts +0 -40
  985. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
  986. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
  987. package/src/components/DataTable/components/index.ts +0 -16
  988. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -342
  989. package/src/components/DataTable/core/ActionManager.ts +0 -235
  990. package/src/components/DataTable/core/ColumnManager.ts +0 -205
  991. package/src/components/DataTable/core/DataManager.ts +0 -188
  992. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  993. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  994. package/src/components/DataTable/core/StateManager.ts +0 -312
  995. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -123
  996. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -305
  997. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -84
  998. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -115
  999. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -100
  1000. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -120
  1001. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -104
  1002. package/src/components/DataTable/core/index.ts +0 -1
  1003. package/src/components/DataTable/core/interfaces.ts +0 -338
  1004. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -521
  1005. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -167
  1006. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -124
  1007. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -117
  1008. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -102
  1009. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -596
  1010. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -53
  1011. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -214
  1012. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -448
  1013. package/src/components/DataTable/hooks/index.ts +0 -13
  1014. package/src/components/DataTable/types.ts +0 -761
  1015. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -612
  1016. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
  1017. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -266
  1018. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
  1019. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
  1020. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -247
  1021. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -570
  1022. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
  1023. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -251
  1024. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -207
  1025. package/src/components/DataTable/utils/index.ts +0 -10
  1026. package/src/components/PublicLayout/index.ts +0 -32
  1027. package/src/components/Select/hooks/useSelectEvents.ts +0 -87
  1028. package/src/components/Select/hooks/useSelectSearch.ts +0 -91
  1029. package/src/components/Select/hooks/useSelectState.ts +0 -104
  1030. package/src/components/Select/utils/text.ts +0 -26
  1031. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -615
  1032. package/src/hooks/__tests__/hooks.integration.test.tsx +0 -607
  1033. package/src/hooks/__tests__/index.unit.test.ts +0 -220
  1034. package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -111
  1035. package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -347
  1036. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -144
  1037. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -776
  1038. package/src/hooks/__tests__/useDataTableState.test.ts +0 -76
  1039. package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
  1040. package/src/hooks/__tests__/useEvents.unit.test.ts +0 -252
  1041. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1112
  1042. package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -916
  1043. package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -129
  1044. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -230
  1045. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -828
  1046. package/src/hooks/__tests__/useFormDialog.test.ts +0 -478
  1047. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
  1048. package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
  1049. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -910
  1050. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -294
  1051. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
  1052. package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
  1053. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
  1054. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  1055. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  1056. package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -88
  1057. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -785
  1058. package/src/hooks/__tests__/usePublicEvent.test.ts +0 -678
  1059. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -630
  1060. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -951
  1061. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -443
  1062. package/src/hooks/__tests__/useQueryCache.test.ts +0 -144
  1063. package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
  1064. package/src/hooks/__tests__/useSessionDraft.test.ts +0 -163
  1065. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
  1066. package/src/hooks/__tests__/useStorage.unit.test.ts +0 -751
  1067. package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
  1068. package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
  1069. package/src/hooks/public/index.ts +0 -36
  1070. package/src/hooks/public/usePublicFileDisplay.ts +0 -504
  1071. package/src/hooks/useFileDisplay.ts +0 -715
  1072. package/src/providers/OrganisationProvider.tsx +0 -92
  1073. package/src/providers/__tests__/AuthProvider.test.tsx +0 -287
  1074. package/src/providers/__tests__/EventProvider.test.tsx +0 -551
  1075. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  1076. package/src/providers/__tests__/InactivityProvider.test.tsx +0 -572
  1077. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -617
  1078. package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -424
  1079. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -596
  1080. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -263
  1081. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -294
  1082. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -434
  1083. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -313
  1084. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -486
  1085. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -399
  1086. package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -813
  1087. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
  1088. package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
  1089. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -392
  1090. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -258
  1091. package/src/rbac/__tests__/rbac-functions.test.ts +0 -647
  1092. package/src/rbac/__tests__/rbac-integration.test.ts +0 -524
  1093. package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
  1094. package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -282
  1095. package/src/rbac/audit-enhanced.ts +0 -384
  1096. package/src/rbac/compliance/database-validator.ts +0 -165
  1097. package/src/rbac/compliance/index.ts +0 -48
  1098. package/src/rbac/compliance/pattern-detector.ts +0 -553
  1099. package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
  1100. package/src/rbac/compliance/runtime-compliance.ts +0 -99
  1101. package/src/rbac/compliance/setup-validator.ts +0 -131
  1102. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -975
  1103. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -248
  1104. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -242
  1105. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1107
  1106. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -184
  1107. package/src/rbac/components/index.ts +0 -26
  1108. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -432
  1109. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -579
  1110. package/src/rbac/hooks/index.ts +0 -34
  1111. package/src/rbac/hooks/permissions/index.ts +0 -4
  1112. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  1113. package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -128
  1114. package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -53
  1115. package/src/rbac/utils/__tests__/eventContext.test.ts +0 -433
  1116. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
  1117. package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -39
  1118. package/src/services/__tests__/AuthService.test.ts +0 -1332
  1119. package/src/services/__tests__/BaseService.test.ts +0 -314
  1120. package/src/services/__tests__/EventService.eventColours.test.ts +0 -76
  1121. package/src/services/__tests__/EventService.test.ts +0 -1025
  1122. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -411
  1123. package/src/services/__tests__/InactivityService.test.ts +0 -654
  1124. package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
  1125. package/src/services/__tests__/OrganisationService.test.ts +0 -1176
  1126. package/src/theming/__tests__/parseEventColours.test.ts +0 -321
  1127. package/src/theming/__tests__/runtime.test.ts +0 -569
  1128. package/src/types/__tests__/file-reference.test.ts +0 -447
  1129. package/src/types/__tests__/guards.test.ts +0 -246
  1130. package/src/types/__tests__/organisation.roles.test.ts +0 -55
  1131. package/src/types/__tests__/organisation.test.ts +0 -1133
  1132. package/src/types/__tests__/theme.test.ts +0 -830
  1133. package/src/types/__tests__/type-validation.test.ts +0 -526
  1134. package/src/types/__tests__/validation.test.ts +0 -731
  1135. package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
  1136. package/src/utils/__tests__/audit.unit.test.ts +0 -69
  1137. package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
  1138. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -339
  1139. package/src/utils/__tests__/cn.unit.test.ts +0 -34
  1140. package/src/utils/__tests__/debugLogger.test.ts +0 -417
  1141. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
  1142. package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -318
  1143. package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
  1144. package/src/utils/__tests__/formatting.unit.test.ts +0 -99
  1145. package/src/utils/__tests__/index.unit.test.ts +0 -251
  1146. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -321
  1147. package/src/utils/__tests__/logger.unit.test.ts +0 -398
  1148. package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
  1149. package/src/utils/__tests__/performanceBenchmark.test.ts +0 -175
  1150. package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -253
  1151. package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
  1152. package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
  1153. package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
  1154. package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
  1155. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -335
  1156. package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
  1157. package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
  1158. package/src/utils/__tests__/security.unit.test.ts +0 -149
  1159. package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
  1160. package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
  1161. package/src/utils/__tests__/timezone.test.ts +0 -345
  1162. package/src/utils/__tests__/validation.unit.test.ts +0 -308
  1163. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
  1164. package/src/utils/app/appNameResolver.simple.test.ts +0 -212
  1165. package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -875
  1166. package/src/utils/google-places/index.ts +0 -26
  1167. package/src/utils/location/index.ts +0 -16
  1168. package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -135
  1169. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -123
  1170. package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
  1171. package/src/utils/storage/__tests__/index.unit.test.ts +0 -16
  1172. package/src/utils/storage/index.ts +0 -67
  1173. package/src/utils/timezone/index.ts +0 -17
  1174. package/src/utils/validation/__tests__/csrf.test.ts +0 -105
  1175. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -598
  1176. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -92
  1177. package/src/utils/validation/__tests__/validationUtils.test.ts +0 -72
  1178. package/src/utils/validation/index.ts +0 -73
  1179. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  1180. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  1181. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  1182. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -1,2177 +0,0 @@
1
- import { emitAuditEvent, createAuditManager, setGlobalAuditManager } from './chunk-AHU7G2R5.js';
2
- import { createLogger } from './chunk-TTRFSOKR.js';
3
-
4
- // src/rbac/types.ts
5
- var RBACError = class extends Error {
6
- constructor(message, code, context) {
7
- super(message);
8
- this.code = code;
9
- this.context = context;
10
- this.name = "RBACError";
11
- }
12
- };
13
- var PermissionDeniedError = class extends RBACError {
14
- constructor(permission, context) {
15
- super(
16
- `Permission denied: ${permission}`,
17
- "PERMISSION_DENIED",
18
- { permission, ...context }
19
- );
20
- this.name = "PermissionDeniedError";
21
- }
22
- };
23
- var OrganisationContextRequiredError = class extends RBACError {
24
- constructor() {
25
- super(
26
- "Organisation context is required for this operation",
27
- "ORGANISATION_CONTEXT_REQUIRED"
28
- );
29
- this.name = "OrganisationContextRequiredError";
30
- }
31
- };
32
- var EventContextRequiredError = class extends RBACError {
33
- constructor() {
34
- super(
35
- "Event context is required for this operation",
36
- "EVENT_CONTEXT_REQUIRED"
37
- );
38
- this.name = "EventContextRequiredError";
39
- }
40
- };
41
- var RBACNotInitializedError = class extends RBACError {
42
- constructor() {
43
- super(
44
- "RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup",
45
- "RBAC_NOT_INITIALIZED"
46
- );
47
- this.name = "RBACNotInitializedError";
48
- }
49
- };
50
- var InvalidScopeError = class extends RBACError {
51
- constructor(scope, reason) {
52
- super(
53
- `Invalid scope provided: ${JSON.stringify(scope)}. ${reason}`,
54
- "INVALID_SCOPE",
55
- { scope, reason }
56
- );
57
- this.name = "InvalidScopeError";
58
- }
59
- };
60
- var MissingUserContextError = class extends RBACError {
61
- constructor() {
62
- super(
63
- "User context is required but not available. Make sure to wrap your app with an auth provider.",
64
- "MISSING_USER_CONTEXT"
65
- );
66
- this.name = "MissingUserContextError";
67
- }
68
- };
69
-
70
- // src/rbac/cache.ts
71
- var RBACCache = class {
72
- constructor() {
73
- this.cache = /* @__PURE__ */ new Map();
74
- this.sessionCache = /* @__PURE__ */ new Map();
75
- this.TTL = 120 * 1e3;
76
- // 120 seconds (short-term) - increased from 60s
77
- this.SESSION_TTL = 15 * 60 * 1e3;
78
- // 15 minutes (session-level) - increased from 5min
79
- this.invalidationCallbacks = /* @__PURE__ */ new Set();
80
- }
81
- /**
82
- * Get a value from the cache
83
- *
84
- * Checks both short-term cache and session cache.
85
- *
86
- * @param key - Cache key
87
- * @param useSessionCache - Whether to check session cache (default: true)
88
- * @returns Cached value or null if not found/expired
89
- */
90
- get(key, useSessionCache = true) {
91
- const now = Date.now();
92
- const entry = this.cache.get(key);
93
- if (entry && now <= entry.expires) {
94
- return entry.data;
95
- }
96
- if (entry && now > entry.expires) {
97
- this.cache.delete(key);
98
- }
99
- if (useSessionCache) {
100
- const sessionEntry = this.sessionCache.get(key);
101
- if (sessionEntry && now <= sessionEntry.expires) {
102
- return sessionEntry.data;
103
- }
104
- if (sessionEntry && now > sessionEntry.expires) {
105
- this.sessionCache.delete(key);
106
- }
107
- }
108
- return null;
109
- }
110
- /**
111
- * Set a value in the cache
112
- *
113
- * @param key - Cache key
114
- * @param data - Data to cache
115
- * @param ttl - Time to live in milliseconds (defaults to 60s)
116
- * @param useSessionCache - Whether to also store in session cache (default: false for page-level checks)
117
- */
118
- set(key, data, ttl = this.TTL, useSessionCache = false) {
119
- const now = Date.now();
120
- const expires = ttl <= 0 ? now - 1 : now + ttl;
121
- this.cache.set(key, {
122
- data,
123
- expires
124
- });
125
- if (useSessionCache) {
126
- const sessionExpires = ttl <= 0 ? now - 1 : now + this.SESSION_TTL;
127
- this.sessionCache.set(key, {
128
- data,
129
- expires: sessionExpires
130
- });
131
- }
132
- }
133
- /**
134
- * Delete a specific key from the cache
135
- *
136
- * @param key - Cache key to delete
137
- */
138
- delete(key) {
139
- this.cache.delete(key);
140
- this.sessionCache.delete(key);
141
- }
142
- /**
143
- * Invalidate cache entries matching a pattern
144
- *
145
- * @param pattern - Pattern to match against cache keys
146
- */
147
- invalidate(pattern) {
148
- const trimmedPattern = pattern?.trim();
149
- if (!trimmedPattern) {
150
- return;
151
- }
152
- const matcher = this.createMatcher(trimmedPattern);
153
- const keysToDelete = [];
154
- for (const key of this.cache.keys()) {
155
- if (matcher(key)) {
156
- keysToDelete.push(key);
157
- }
158
- }
159
- for (const key of this.sessionCache.keys()) {
160
- if (matcher(key) && !keysToDelete.includes(key)) {
161
- keysToDelete.push(key);
162
- }
163
- }
164
- keysToDelete.forEach((key) => {
165
- this.cache.delete(key);
166
- this.sessionCache.delete(key);
167
- });
168
- this.invalidationCallbacks.forEach((callback) => callback(trimmedPattern));
169
- }
170
- createMatcher(pattern) {
171
- if (pattern.includes("*")) {
172
- const escapedSegments = pattern.split("*").map((segment) => segment.replace(/[|\\{}()[\]^$+?.-]/g, "\\$&"));
173
- const regexPattern = escapedSegments.join(".*");
174
- const regex = new RegExp(regexPattern);
175
- return (key) => regex.test(key);
176
- }
177
- return (key) => key.includes(pattern);
178
- }
179
- /**
180
- * Clear all cache entries
181
- */
182
- clear() {
183
- this.cache.clear();
184
- this.sessionCache.clear();
185
- }
186
- /**
187
- * Get cache statistics
188
- */
189
- getStats() {
190
- return {
191
- size: this.cache.size,
192
- sessionSize: this.sessionCache.size,
193
- ttl: this.TTL,
194
- sessionTtl: this.SESSION_TTL,
195
- keys: Array.from(this.cache.keys())
196
- };
197
- }
198
- /**
199
- * Add an invalidation callback
200
- *
201
- * @param callback - Function to call when cache is invalidated
202
- */
203
- onInvalidate(callback) {
204
- this.invalidationCallbacks.add(callback);
205
- return () => {
206
- this.invalidationCallbacks.delete(callback);
207
- };
208
- }
209
- /**
210
- * Generate cache key for permission check (simplified signature)
211
- *
212
- * @param userId - User ID
213
- * @param permission - Permission string
214
- * @param organisationId - Organisation ID (optional)
215
- * @param eventId - Event ID (optional)
216
- * @param appId - App ID (optional)
217
- * @param pageId - Page ID (optional)
218
- * @returns String cache key
219
- */
220
- static generateKey(userId, permission, organisationId, eventId, appId, pageId) {
221
- const parts = [
222
- "perm",
223
- userId,
224
- organisationId || "null",
225
- eventId || "null",
226
- appId || "null",
227
- permission || "null",
228
- pageId || "null"
229
- ];
230
- return parts.join(":");
231
- }
232
- /**
233
- * Generate cache key for permission check (object signature)
234
- *
235
- * @param key - Permission cache key object
236
- * @returns String cache key
237
- */
238
- static generatePermissionKey(key) {
239
- const parts = [
240
- "perm",
241
- key.userId,
242
- key.organisationId || "null",
243
- key.eventId || "null",
244
- key.appId || "null",
245
- key.permission || "null",
246
- key.pageId || "null"
247
- ];
248
- return parts.join(":");
249
- }
250
- /**
251
- * Generate cache key for access level
252
- *
253
- * @param userId - User ID
254
- * @param organisationId - Organisation ID
255
- * @param eventId - Event ID (optional)
256
- * @param appId - App ID (optional)
257
- * @returns String cache key
258
- */
259
- static generateAccessLevelKey(userId, organisationId, eventId, appId) {
260
- const parts = [
261
- "access",
262
- userId,
263
- organisationId,
264
- eventId || "null",
265
- appId || "null"
266
- ];
267
- return parts.join(":");
268
- }
269
- /**
270
- * Generate cache key for permission map
271
- *
272
- * @param userId - User ID
273
- * @param organisationId - Organisation ID
274
- * @param eventId - Event ID (optional)
275
- * @param appId - App ID (optional)
276
- * @returns String cache key
277
- */
278
- static generatePermissionMapKey(userId, organisationId, eventId, appId) {
279
- const parts = [
280
- "map",
281
- userId,
282
- organisationId,
283
- eventId || "null",
284
- appId || "null"
285
- ];
286
- return parts.join(":");
287
- }
288
- };
289
- var rbacCache = new RBACCache();
290
- var CACHE_PATTERNS = {
291
- USER: (userId) => `:${userId}:`,
292
- ORGANISATION: (organisationId) => `:${organisationId}:`,
293
- EVENT: (eventId) => `:${eventId}:`,
294
- APP: (appId) => `:${appId}`,
295
- PERMISSION: (userId, organisationId) => `perm:${userId}:${organisationId}:`
296
- };
297
-
298
- // src/rbac/cache-invalidation.ts
299
- var log = createLogger("RBACCache");
300
- var INVALIDATION_PATTERNS = {
301
- // User-level invalidation
302
- USER_ROLES_CHANGED: (userId) => [
303
- CACHE_PATTERNS.USER(userId),
304
- `perm:${userId}:*`,
305
- `access:${userId}:*`,
306
- `map:${userId}:*`
307
- ],
308
- // Organisation-level invalidation
309
- ORGANISATION_PERMISSIONS_CHANGED: (organisationId) => [
310
- CACHE_PATTERNS.ORGANISATION(organisationId),
311
- `perm:*:${organisationId}:*`,
312
- `access:*:${organisationId}:*`,
313
- `map:*:${organisationId}:*`
314
- ],
315
- // Event-level invalidation
316
- EVENT_PERMISSIONS_CHANGED: (eventId) => [
317
- CACHE_PATTERNS.EVENT(eventId),
318
- `perm:*:*:${eventId}:*`,
319
- `access:*:*:${eventId}:*`,
320
- `map:*:*:${eventId}:*`
321
- ],
322
- // App-level invalidation
323
- APP_PERMISSIONS_CHANGED: (appId) => [
324
- CACHE_PATTERNS.APP(appId),
325
- `perm:*:*:*:${appId}:*`,
326
- `access:*:*:*:${appId}`,
327
- `map:*:*:*:${appId}`
328
- ],
329
- // Page-level invalidation
330
- PAGE_PERMISSIONS_CHANGED: (pageId) => [
331
- `perm:*:*:*:*:${pageId}`,
332
- `map:*:*:*:*`
333
- ]
334
- };
335
- var RBACCacheInvalidationManager = class {
336
- constructor(supabase) {
337
- this.invalidationCallbacks = /* @__PURE__ */ new Set();
338
- this.channels = [];
339
- this.supabase = supabase;
340
- this.setupRealtimeSubscriptions();
341
- }
342
- /**
343
- * Add a callback for cache invalidation events
344
- *
345
- * @param callback - Function to call when cache is invalidated
346
- * @returns Unsubscribe function
347
- */
348
- onInvalidation(callback) {
349
- this.invalidationCallbacks.add(callback);
350
- return () => this.invalidationCallbacks.delete(callback);
351
- }
352
- /**
353
- * Invalidate cache for a specific user
354
- *
355
- * @param userId - User ID
356
- * @param reason - Reason for invalidation
357
- */
358
- invalidateUser(userId, reason) {
359
- const patterns = INVALIDATION_PATTERNS.USER_ROLES_CHANGED(userId);
360
- this.invalidatePatterns(patterns, reason);
361
- }
362
- /**
363
- * Invalidate cache for a specific organisation
364
- *
365
- * @param organisationId - Organisation ID
366
- * @param reason - Reason for invalidation
367
- */
368
- invalidateOrganisation(organisationId, reason) {
369
- const patterns = INVALIDATION_PATTERNS.ORGANISATION_PERMISSIONS_CHANGED(organisationId);
370
- this.invalidatePatterns(patterns, reason);
371
- }
372
- /**
373
- * Invalidate cache for a specific event
374
- *
375
- * @param eventId - Event ID
376
- * @param reason - Reason for invalidation
377
- */
378
- invalidateEvent(eventId, reason) {
379
- const patterns = INVALIDATION_PATTERNS.EVENT_PERMISSIONS_CHANGED(eventId);
380
- this.invalidatePatterns(patterns, reason);
381
- }
382
- /**
383
- * Invalidate cache for a specific app
384
- *
385
- * @param appId - App ID
386
- * @param reason - Reason for invalidation
387
- */
388
- invalidateApp(appId, reason) {
389
- const patterns = INVALIDATION_PATTERNS.APP_PERMISSIONS_CHANGED(appId);
390
- this.invalidatePatterns(patterns, reason);
391
- }
392
- /**
393
- * Invalidate cache for a specific page
394
- *
395
- * @param pageId - Page ID
396
- * @param reason - Reason for invalidation
397
- */
398
- invalidatePage(pageId, reason) {
399
- const patterns = INVALIDATION_PATTERNS.PAGE_PERMISSIONS_CHANGED(pageId);
400
- this.invalidatePatterns(patterns, reason);
401
- }
402
- /**
403
- * Invalidate cache patterns and notify callbacks
404
- *
405
- * @param patterns - Array of cache patterns to invalidate
406
- * @param reason - Reason for invalidation
407
- */
408
- invalidatePatterns(patterns, reason) {
409
- log.debug(`Invalidating patterns: ${patterns.join(", ")} (${reason})`);
410
- patterns.forEach((pattern) => {
411
- rbacCache.invalidate(pattern);
412
- });
413
- this.invalidationCallbacks.forEach((callback) => {
414
- patterns.forEach((pattern) => callback(pattern));
415
- });
416
- emitAuditEvent({
417
- type: "permission_check",
418
- userId: "system",
419
- organisationId: "00000000-0000-0000-0000-000000000000",
420
- permission: "cache:invalidate",
421
- decision: true,
422
- source: "api",
423
- duration_ms: 0,
424
- metadata: {
425
- reason,
426
- patterns,
427
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
428
- cache_invalidation: true
429
- }
430
- }).catch((error) => {
431
- log.warn("Failed to log cache invalidation audit event:", error);
432
- });
433
- }
434
- /**
435
- * Cleanup subscriptions only (not all callbacks)
436
- * Used internally to cleanup before setting up new subscriptions
437
- */
438
- cleanupSubscriptions() {
439
- this.channels.forEach((channel) => {
440
- try {
441
- if (channel && typeof channel.unsubscribe === "function") {
442
- channel.unsubscribe();
443
- }
444
- } catch (error) {
445
- log.warn("Failed to unsubscribe from channel:", error);
446
- }
447
- });
448
- this.channels = [];
449
- }
450
- /**
451
- * Setup realtime subscriptions for automatic cache invalidation
452
- * Always cleans up existing subscriptions before setting up new ones to prevent duplicates
453
- */
454
- setupRealtimeSubscriptions() {
455
- this.cleanupSubscriptions();
456
- if (!this.supabase.channel || typeof this.supabase.channel !== "function") {
457
- log.debug("Realtime not available, skipping subscriptions");
458
- return;
459
- }
460
- const orgRolesChannel = this.supabase.channel("rbac_organisation_roles_changes").on("postgres_changes", {
461
- event: "*",
462
- schema: "public",
463
- table: "rbac_organisation_roles"
464
- }, (payload) => {
465
- const { organisation_id, user_id } = payload.new || payload.old || {};
466
- if (organisation_id) {
467
- this.invalidateOrganisation(organisation_id, `organisation_role_${payload.eventType}`);
468
- }
469
- if (user_id) {
470
- this.invalidateUser(user_id, `organisation_role_${payload.eventType}`);
471
- }
472
- });
473
- const orgRolesSubscription = orgRolesChannel.subscribe();
474
- this.channels.push(orgRolesSubscription);
475
- const eventAppRolesChannel = this.supabase.channel("rbac_event_app_roles_changes").on("postgres_changes", {
476
- event: "*",
477
- schema: "public",
478
- table: "rbac_event_app_roles"
479
- }, (payload) => {
480
- const { organisation_id, user_id, event_id, app_id } = payload.new || payload.old || {};
481
- if (organisation_id) {
482
- this.invalidateOrganisation(organisation_id, `event_app_role_${payload.eventType}`);
483
- }
484
- if (user_id) {
485
- this.invalidateUser(user_id, `event_app_role_${payload.eventType}`);
486
- }
487
- if (event_id) {
488
- this.invalidateEvent(event_id, `event_app_role_${payload.eventType}`);
489
- }
490
- if (app_id) {
491
- this.invalidateApp(app_id, `event_app_role_${payload.eventType}`);
492
- }
493
- });
494
- const eventAppRolesSubscription = eventAppRolesChannel.subscribe();
495
- this.channels.push(eventAppRolesSubscription);
496
- const globalRolesChannel = this.supabase.channel("rbac_global_roles_changes").on("postgres_changes", {
497
- event: "*",
498
- schema: "public",
499
- table: "rbac_global_roles"
500
- }, (payload) => {
501
- const { user_id } = payload.new || payload.old || {};
502
- if (user_id) {
503
- this.invalidateUser(user_id, `global_role_${payload.eventType}`);
504
- }
505
- });
506
- const globalRolesSubscription = globalRolesChannel.subscribe();
507
- this.channels.push(globalRolesSubscription);
508
- const pagePermissionsChannel = this.supabase.channel("rbac_page_permissions_changes").on("postgres_changes", {
509
- event: "*",
510
- schema: "public",
511
- table: "rbac_page_permissions"
512
- }, (payload) => {
513
- const { organisation_id, app_page_id, role_id } = payload.new || payload.old || {};
514
- if (organisation_id) {
515
- this.invalidateOrganisation(organisation_id, `page_permission_${payload.eventType}`);
516
- }
517
- if (app_page_id) {
518
- this.invalidatePage(app_page_id, `page_permission_${payload.eventType}`);
519
- }
520
- });
521
- const pagePermissionsSubscription = pagePermissionsChannel.subscribe();
522
- this.channels.push(pagePermissionsSubscription);
523
- }
524
- /**
525
- * Cleanup all realtime subscriptions
526
- * Call this when the manager is no longer needed to prevent memory leaks
527
- */
528
- cleanup() {
529
- this.channels.forEach((channel) => {
530
- try {
531
- if (channel && typeof channel.unsubscribe === "function") {
532
- channel.unsubscribe();
533
- }
534
- } catch (error) {
535
- log.warn("Failed to unsubscribe from channel:", error);
536
- }
537
- });
538
- this.channels = [];
539
- this.invalidationCallbacks.clear();
540
- }
541
- /**
542
- * Manually trigger cache invalidation for all users in an organisation
543
- *
544
- * @param organisationId - Organisation ID
545
- * @param reason - Reason for invalidation
546
- */
547
- async invalidateAllUsersInOrganisation(organisationId, reason) {
548
- const { data: users } = await this.supabase.from("rbac_organisation_roles").select("user_id").eq("organisation_id", organisationId).eq("is_active", true);
549
- if (users) {
550
- users.forEach(({ user_id }) => {
551
- this.invalidateUser(user_id, reason);
552
- });
553
- }
554
- }
555
- /**
556
- * Clear all cache entries
557
- */
558
- clearAllCache() {
559
- log.debug("Clearing all cache entries");
560
- rbacCache.clear();
561
- }
562
- };
563
- var globalCacheInvalidationManager = null;
564
- function initializeCacheInvalidation(supabase) {
565
- if (globalCacheInvalidationManager) {
566
- globalCacheInvalidationManager.cleanup();
567
- }
568
- globalCacheInvalidationManager = new RBACCacheInvalidationManager(supabase);
569
- return globalCacheInvalidationManager;
570
- }
571
-
572
- // src/rbac/errors.ts
573
- var RATE_LIMIT_STATUS_CODES = /* @__PURE__ */ new Set([429]);
574
- var AUTH_STATUS_CODES = /* @__PURE__ */ new Set([401]);
575
- var AUTHZ_STATUS_CODES = /* @__PURE__ */ new Set([403]);
576
- function normalize(value) {
577
- if (!value) {
578
- return "";
579
- }
580
- if (typeof value === "string") {
581
- return value.toLowerCase();
582
- }
583
- if (value instanceof Error && typeof value.message === "string") {
584
- return value.message.toLowerCase();
585
- }
586
- return String(value).toLowerCase();
587
- }
588
- function categorizeError(error) {
589
- if (error instanceof PermissionDeniedError) {
590
- return "authorization_error" /* AUTHORIZATION */;
591
- }
592
- if (error instanceof OrganisationContextRequiredError || error instanceof InvalidScopeError) {
593
- return "validation_error" /* VALIDATION */;
594
- }
595
- if (error instanceof MissingUserContextError) {
596
- return "authentication_error" /* AUTHENTICATION */;
597
- }
598
- if (error instanceof RBACError) {
599
- switch (error.code) {
600
- case "PERMISSION_DENIED":
601
- return "authorization_error" /* AUTHORIZATION */;
602
- case "ORGANISATION_CONTEXT_REQUIRED":
603
- case "INVALID_SCOPE":
604
- return "validation_error" /* VALIDATION */;
605
- case "MISSING_USER_CONTEXT":
606
- return "authentication_error" /* AUTHENTICATION */;
607
- }
608
- }
609
- if (error && typeof error === "object") {
610
- const status = error.status;
611
- if (typeof status === "number") {
612
- if (RATE_LIMIT_STATUS_CODES.has(status)) {
613
- return "rate_limit_error" /* RATE_LIMIT */;
614
- }
615
- if (AUTH_STATUS_CODES.has(status)) {
616
- return "authentication_error" /* AUTHENTICATION */;
617
- }
618
- if (AUTHZ_STATUS_CODES.has(status)) {
619
- return "authorization_error" /* AUTHORIZATION */;
620
- }
621
- if (status >= 500) {
622
- return "database_error" /* DATABASE */;
623
- }
624
- }
625
- const codeValue = normalize(error.code);
626
- if (codeValue) {
627
- if (codeValue.includes("network")) {
628
- return "network_error" /* NETWORK */;
629
- }
630
- if (codeValue.includes("postgres") || codeValue.includes("database") || codeValue.includes("db")) {
631
- return "database_error" /* DATABASE */;
632
- }
633
- if (codeValue.includes("rate")) {
634
- return "rate_limit_error" /* RATE_LIMIT */;
635
- }
636
- if (codeValue.includes("auth")) {
637
- return "authentication_error" /* AUTHENTICATION */;
638
- }
639
- if (codeValue.includes("permission")) {
640
- return "authorization_error" /* AUTHORIZATION */;
641
- }
642
- if (codeValue.includes("scope") || codeValue.includes("invalid")) {
643
- return "validation_error" /* VALIDATION */;
644
- }
645
- }
646
- }
647
- const message = normalize(error);
648
- if (message.includes("timeout") || message.includes("network") || message.includes("fetch")) {
649
- return "network_error" /* NETWORK */;
650
- }
651
- if (message.includes("postgres") || message.includes("database") || message.includes("connection")) {
652
- return "database_error" /* DATABASE */;
653
- }
654
- if (message.includes("rate limit") || message.includes("too many requests")) {
655
- return "rate_limit_error" /* RATE_LIMIT */;
656
- }
657
- if (message.includes("permission") || message.includes("forbidden")) {
658
- return "authorization_error" /* AUTHORIZATION */;
659
- }
660
- if (message.includes("auth") || message.includes("token") || message.includes("session")) {
661
- return "authentication_error" /* AUTHENTICATION */;
662
- }
663
- if (message.includes("invalid") || message.includes("scope") || message.includes("validation")) {
664
- return "validation_error" /* VALIDATION */;
665
- }
666
- return "unknown_error" /* UNKNOWN */;
667
- }
668
- function mapErrorCategoryToSecurityEventType(category) {
669
- switch (category) {
670
- case "authorization_error" /* AUTHORIZATION */:
671
- return "permission_denied";
672
- case "network_error" /* NETWORK */:
673
- return "network_error";
674
- case "database_error" /* DATABASE */:
675
- return "database_error";
676
- case "validation_error" /* VALIDATION */:
677
- return "validation_error";
678
- case "rate_limit_error" /* RATE_LIMIT */:
679
- return "rate_limit_error";
680
- case "authentication_error" /* AUTHENTICATION */:
681
- return "authentication_error";
682
- case "unknown_error" /* UNKNOWN */:
683
- default:
684
- return "unknown_error";
685
- }
686
- }
687
-
688
- // src/rbac/security.ts
689
- var log2 = createLogger("RBACSecurity");
690
- var RBACSecurityValidator = class {
691
- /**
692
- * Validate permission string format
693
- * @param permission - Permission string to validate
694
- * @returns True if valid, false otherwise
695
- */
696
- static validatePermission(permission) {
697
- if (typeof permission !== "string" || permission.length === 0) {
698
- return false;
699
- }
700
- const permissionRegex = /^(read|create|update|delete):[a-z0-9._-]+$/;
701
- return permissionRegex.test(permission);
702
- }
703
- /**
704
- * Validate UUID format
705
- * @param uuid - UUID string to validate
706
- * @returns True if valid, false otherwise
707
- */
708
- static validateUUID(uuid) {
709
- if (typeof uuid !== "string" || uuid.length === 0) {
710
- return false;
711
- }
712
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
713
- return uuidRegex.test(uuid);
714
- }
715
- /**
716
- * Validate scope object
717
- * @param scope - Scope object to validate
718
- * @returns True if valid, false otherwise
719
- */
720
- static validateScope(scope) {
721
- if (!scope || typeof scope !== "object") {
722
- return false;
723
- }
724
- if (scope.organisationId !== void 0) {
725
- if (typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
726
- return false;
727
- }
728
- if (scope.organisationId && !this.validateUUID(scope.organisationId)) {
729
- return false;
730
- }
731
- }
732
- if (scope.eventId && typeof scope.eventId !== "string") {
733
- return false;
734
- }
735
- if (scope.appId && !this.validateUUID(scope.appId)) {
736
- return false;
737
- }
738
- return !!(scope.organisationId || scope.eventId || scope.appId);
739
- }
740
- /**
741
- * Sanitize input string to prevent injection attacks
742
- * @param input - Input string to sanitize
743
- * @returns Sanitized string
744
- */
745
- static sanitizeInput(input) {
746
- if (typeof input !== "string") {
747
- return "";
748
- }
749
- return input.replace(/<[^>]*>/g, "").replace(/[<>\"'&]/g, "").replace(/[;()]/g, "").replace(/javascript:/gi, "").replace(/data:/gi, "").trim();
750
- }
751
- /**
752
- * Validate user ID format
753
- * @param userId - User ID to validate
754
- * @returns True if valid, false otherwise
755
- */
756
- static validateUserId(userId) {
757
- return this.validateUUID(userId);
758
- }
759
- /**
760
- * Check if permission is a wildcard permission
761
- * @param permission - Permission string to check
762
- * @returns True if wildcard, false otherwise
763
- */
764
- static isWildcardPermission(permission) {
765
- return permission.includes("*") || permission.endsWith(":*");
766
- }
767
- /**
768
- * Validate permission hierarchy
769
- * @param permission - Permission to validate
770
- * @param requiredOperation - Required operation
771
- * @returns True if permission matches or is higher in hierarchy
772
- */
773
- static validatePermissionHierarchy(permission, requiredOperation) {
774
- if (!this.validatePermission(permission)) {
775
- return false;
776
- }
777
- const [operation] = permission.split(":");
778
- const hierarchy = ["read", "create", "update", "delete"];
779
- const permissionLevel = hierarchy.indexOf(operation);
780
- const requiredLevel = hierarchy.indexOf(requiredOperation);
781
- if (permissionLevel === -1 || requiredLevel === -1) {
782
- return false;
783
- }
784
- return permissionLevel >= requiredLevel;
785
- }
786
- /**
787
- * Rate limiting check (placeholder for future implementation)
788
- * @param userId - User ID
789
- * @param operation - Operation being performed
790
- * @returns True if within rate limit, false otherwise
791
- */
792
- static async checkRateLimit(userId, operation) {
793
- return true;
794
- }
795
- // Only warn once per 5 seconds per user
796
- static logSecurityEvent(event) {
797
- const securityEvent = {
798
- ...event,
799
- timestamp: event.timestamp || /* @__PURE__ */ new Date(),
800
- severity: this.getEventSeverity(event.type)
801
- };
802
- if (event.type === "rate_limit_exceeded") {
803
- const now = Date.now();
804
- const userWarning = this.rateLimitWarningCount.get(event.userId);
805
- if (userWarning) {
806
- const timeSinceLastWarning = now - userWarning.lastWarning;
807
- if (timeSinceLastWarning < this.RATE_LIMIT_WARNING_THROTTLE_MS) {
808
- userWarning.count++;
809
- this.rateLimitWarningCount.set(event.userId, userWarning);
810
- return;
811
- } else {
812
- log2.warn("Security event (throttled):", {
813
- ...securityEvent,
814
- details: {
815
- ...securityEvent.details,
816
- suppressedWarnings: userWarning.count,
817
- message: `Rate limit exceeded (${userWarning.count + 1} times in last ${Math.round(timeSinceLastWarning / 1e3)}s)`
818
- }
819
- });
820
- this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });
821
- return;
822
- }
823
- } else {
824
- this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });
825
- log2.warn("Security event:", securityEvent);
826
- return;
827
- }
828
- }
829
- log2.warn("Security event:", securityEvent);
830
- }
831
- /**
832
- * Get severity level for security event
833
- * @param eventType - Type of security event
834
- * @returns Severity level
835
- */
836
- static getEventSeverity(eventType) {
837
- switch (eventType) {
838
- case "permission_denied":
839
- return "low";
840
- case "invalid_input":
841
- case "rate_limit_exceeded":
842
- case "rate_limit_error":
843
- case "network_error":
844
- return "medium";
845
- case "validation_error":
846
- return "high";
847
- case "authentication_error":
848
- case "database_error":
849
- return "critical";
850
- case "suspicious_activity":
851
- case "unknown_error":
852
- return "high";
853
- default:
854
- return "low";
855
- }
856
- }
857
- };
858
- /**
859
- * Log security event for monitoring
860
- * @param event - Security event details
861
- */
862
- RBACSecurityValidator.rateLimitWarningCount = /* @__PURE__ */ new Map();
863
- RBACSecurityValidator.RATE_LIMIT_WARNING_THROTTLE_MS = 5e3;
864
- var DEFAULT_SECURITY_CONFIG = {
865
- enableInputValidation: true,
866
- enableRateLimiting: true,
867
- enableAuditLogging: true,
868
- maxPermissionChecksPerMinute: 1e3,
869
- // Increased from 100 to 1000 for normal app usage
870
- suspiciousActivityThreshold: 10
871
- };
872
- var RBACSecurityMiddleware = class {
873
- constructor(config = DEFAULT_SECURITY_CONFIG) {
874
- /**
875
- * In-memory rate limiting cache (sliding window)
876
- * Note: For production, this should use Redis or Supabase Edge Functions
877
- */
878
- this.rateLimitCache = /* @__PURE__ */ new Map();
879
- this.config = config;
880
- this._startCleanupInterval();
881
- }
882
- /**
883
- * Start periodic cleanup of expired entries
884
- */
885
- _startCleanupInterval() {
886
- setInterval(() => {
887
- this.clearExpiredEntries();
888
- }, 5 * 60 * 1e3);
889
- }
890
- /**
891
- * Validate input before processing
892
- * @param input - Input to validate
893
- * @param context - Security context
894
- * @returns Validation result
895
- */
896
- async validateInput(input, context) {
897
- const errors = [];
898
- if (!RBACSecurityValidator.validateUserId(context.userId)) {
899
- errors.push("Invalid user ID format");
900
- }
901
- const isPagePermission = input.permission?.includes(":page.") || !!input.pageId;
902
- const requiresOrgId = !isPagePermission;
903
- if (requiresOrgId) {
904
- if (!context.organisationId) {
905
- errors.push("Organisation ID is required for resource-level permissions");
906
- } else if (!RBACSecurityValidator.validateUUID(context.organisationId)) {
907
- errors.push("Invalid organisation ID format");
908
- }
909
- } else {
910
- if (context.organisationId && !RBACSecurityValidator.validateUUID(context.organisationId)) {
911
- errors.push("Invalid organisation ID format");
912
- }
913
- }
914
- if (input.permission && !RBACSecurityValidator.validatePermission(input.permission)) {
915
- errors.push("Invalid permission format");
916
- }
917
- if (input.scope && !RBACSecurityValidator.validateScope(input.scope)) {
918
- errors.push("Invalid scope format");
919
- }
920
- if (this.config.enableInputValidation) {
921
- if (context.ipAddress && typeof context.ipAddress !== "string") {
922
- errors.push("Invalid IP address format");
923
- }
924
- if (context.userAgent && typeof context.userAgent !== "string") {
925
- errors.push("Invalid user agent format");
926
- }
927
- }
928
- if (errors.length > 0) {
929
- RBACSecurityValidator.logSecurityEvent({
930
- type: "invalid_input",
931
- userId: context.userId,
932
- details: { errors, input: this.sanitizeInput(JSON.stringify(input)) }
933
- });
934
- }
935
- return {
936
- isValid: errors.length === 0,
937
- errors
938
- };
939
- }
940
- /**
941
- * Check rate limiting
942
- * @param context - Security context
943
- * @returns Rate limit check result
944
- */
945
- async checkRateLimit(context) {
946
- if (!this.config.enableRateLimiting) {
947
- return { isAllowed: true, remaining: this.config.maxPermissionChecksPerMinute };
948
- }
949
- const isAllowed = await this._checkRateLimitInternal(context.userId);
950
- const remaining = isAllowed ? this.config.maxPermissionChecksPerMinute - this._getRequestCount(context.userId) : 0;
951
- return {
952
- isAllowed,
953
- remaining: Math.max(0, remaining)
954
- };
955
- }
956
- async _checkRateLimitInternal(userId) {
957
- const now = Date.now();
958
- const windowMs = 60 * 1e3;
959
- const entries = this.rateLimitCache.get(userId) || [];
960
- const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
961
- const requestCount = validEntries.length;
962
- const isAllowed = requestCount < this.config.maxPermissionChecksPerMinute;
963
- if (isAllowed) {
964
- validEntries.push({ timestamp: now });
965
- }
966
- this.rateLimitCache.set(userId, validEntries);
967
- return isAllowed;
968
- }
969
- _getRequestCount(userId) {
970
- const now = Date.now();
971
- const windowMs = 60 * 1e3;
972
- const entries = this.rateLimitCache.get(userId) || [];
973
- const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
974
- return validEntries.length;
975
- }
976
- /**
977
- * Clear old rate limit entries to prevent memory leaks
978
- * Should be called periodically (e.g., every 5 minutes)
979
- */
980
- clearExpiredEntries() {
981
- const now = Date.now();
982
- const windowMs = 60 * 1e3;
983
- for (const [userId, entries] of this.rateLimitCache.entries()) {
984
- const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
985
- if (validEntries.length === 0) {
986
- this.rateLimitCache.delete(userId);
987
- } else {
988
- this.rateLimitCache.set(userId, validEntries);
989
- }
990
- }
991
- }
992
- /**
993
- * Sanitize input data
994
- * @param input - Input to sanitize
995
- * @returns Sanitized input
996
- */
997
- sanitizeInput(input) {
998
- return RBACSecurityValidator.sanitizeInput(input);
999
- }
1000
- };
1001
-
1002
- // src/rbac/config.ts
1003
- var RBACConfigManager = class {
1004
- constructor() {
1005
- this.config = null;
1006
- this.logger = null;
1007
- }
1008
- setConfig(config) {
1009
- this.config = config;
1010
- this.setupLogger();
1011
- }
1012
- getConfig() {
1013
- return this.config;
1014
- }
1015
- getLogger() {
1016
- if (!this.logger) {
1017
- this.logger = this.createDefaultLogger();
1018
- }
1019
- return this.logger;
1020
- }
1021
- setupLogger() {
1022
- if (!this.config) return;
1023
- const { debug = false, logLevel = "warn" } = this.config;
1024
- this.logger = {
1025
- error: (message, ...args) => {
1026
- console.error(`[RBAC ERROR] ${message}`, ...args);
1027
- },
1028
- warn: (message, ...args) => {
1029
- if (logLevel === "warn" || logLevel === "info" || logLevel === "debug") {
1030
- console.warn(`[RBAC WARN] ${message}`, ...args);
1031
- }
1032
- },
1033
- info: (message, ...args) => {
1034
- if (logLevel === "info" || logLevel === "debug") {
1035
- console.info(`[RBAC INFO] ${message}`, ...args);
1036
- }
1037
- },
1038
- debug: (message, ...args) => {
1039
- if (debug && logLevel === "debug") {
1040
- console.debug(`[RBAC DEBUG] ${message}`, ...args);
1041
- }
1042
- }
1043
- };
1044
- }
1045
- createDefaultLogger() {
1046
- return {
1047
- error: (message, ...args) => console.error(`[RBAC ERROR] ${message}`, ...args),
1048
- warn: (message, ...args) => console.warn(`[RBAC WARN] ${message}`, ...args),
1049
- info: (message, ...args) => console.info(`[RBAC INFO] ${message}`, ...args),
1050
- debug: (message, ...args) => console.debug(`[RBAC DEBUG] ${message}`, ...args)
1051
- };
1052
- }
1053
- isDebugMode() {
1054
- return this.config?.debug ?? false;
1055
- }
1056
- isDevelopmentMode() {
1057
- return this.config?.developmentMode ?? false;
1058
- }
1059
- getMockPermissions() {
1060
- return this.config?.mockPermissions ?? null;
1061
- }
1062
- };
1063
- var configManager = new RBACConfigManager();
1064
- function createRBACConfig(config) {
1065
- configManager.setConfig(config);
1066
- return config;
1067
- }
1068
- function getRBACConfig() {
1069
- return configManager.getConfig();
1070
- }
1071
- function getRBACLogger() {
1072
- return configManager.getLogger();
1073
- }
1074
- function isDebugMode() {
1075
- return configManager.isDebugMode();
1076
- }
1077
- function isDevelopmentMode() {
1078
- return configManager.isDevelopmentMode();
1079
- }
1080
-
1081
- // src/rbac/engine.ts
1082
- var RBACEngine = class {
1083
- constructor(supabase, securityConfig) {
1084
- this.supabase = supabase;
1085
- const mergedSecurityConfig = {
1086
- ...DEFAULT_SECURITY_CONFIG,
1087
- ...securityConfig
1088
- };
1089
- this.securityMiddleware = new RBACSecurityMiddleware(mergedSecurityConfig);
1090
- initializeCacheInvalidation(supabase);
1091
- }
1092
- /**
1093
- * Check if a user has a specific permission
1094
- *
1095
- * This method now delegates to the database RPC function for all the heavy lifting.
1096
- *
1097
- * @param input - Permission check input
1098
- * @param securityContext - Security context for validation (required)
1099
- * @returns Promise resolving to permission result
1100
- */
1101
- async isPermitted(input, securityContext) {
1102
- const startTime = Date.now();
1103
- const { userId, permission, scope, pageId } = input;
1104
- let cacheHit = false;
1105
- let cacheSource = "rpc";
1106
- try {
1107
- const validation = await this.securityMiddleware.validateInput(input, securityContext);
1108
- if (!validation.isValid) {
1109
- RBACSecurityValidator.logSecurityEvent({
1110
- type: "invalid_input",
1111
- userId,
1112
- details: { errors: validation.errors, input: JSON.stringify(input) }
1113
- });
1114
- return false;
1115
- }
1116
- const rateLimit = await this.securityMiddleware.checkRateLimit(securityContext);
1117
- if (!rateLimit.isAllowed) {
1118
- RBACSecurityValidator.logSecurityEvent({
1119
- type: "rate_limit_exceeded",
1120
- userId,
1121
- details: { remaining: rateLimit.remaining }
1122
- });
1123
- return false;
1124
- }
1125
- if (!RBACSecurityValidator.validateUserId(userId)) {
1126
- RBACSecurityValidator.logSecurityEvent({
1127
- type: "invalid_input",
1128
- userId,
1129
- details: { error: "Invalid user ID format" }
1130
- });
1131
- return false;
1132
- }
1133
- if (!RBACSecurityValidator.validatePermission(permission)) {
1134
- RBACSecurityValidator.logSecurityEvent({
1135
- type: "invalid_input",
1136
- userId,
1137
- details: { error: "Invalid permission format", permission }
1138
- });
1139
- return false;
1140
- }
1141
- if (!RBACSecurityValidator.validateScope(scope)) {
1142
- RBACSecurityValidator.logSecurityEvent({
1143
- type: "invalid_input",
1144
- userId,
1145
- details: { error: "Invalid scope format", scope }
1146
- });
1147
- return false;
1148
- }
1149
- const cacheKey = RBACCache.generateKey(
1150
- userId,
1151
- permission,
1152
- scope.organisationId,
1153
- scope.eventId,
1154
- scope.appId,
1155
- pageId
1156
- );
1157
- const cached = rbacCache.get(cacheKey);
1158
- if (cached !== null) {
1159
- cacheHit = true;
1160
- cacheSource = "memory";
1161
- return cached;
1162
- }
1163
- const { data, error } = await this.supabase.rpc("rbac_check_permission_simplified", {
1164
- p_user_id: userId,
1165
- p_permission: permission,
1166
- p_organisation_id: scope.organisationId || void 0,
1167
- p_event_id: scope.eventId || void 0,
1168
- p_app_id: scope.appId || void 0,
1169
- p_page_id: pageId || void 0
1170
- });
1171
- if (error) {
1172
- const logger = getRBACLogger();
1173
- logger.error("RPC error:", error);
1174
- const category = categorizeError(error);
1175
- const eventType = mapErrorCategoryToSecurityEventType(category);
1176
- const errorDetails = error;
1177
- RBACSecurityValidator.logSecurityEvent({
1178
- type: eventType,
1179
- userId,
1180
- details: {
1181
- error: errorDetails?.message || "RPC call failed",
1182
- code: errorDetails?.code,
1183
- hint: errorDetails?.hint,
1184
- details: errorDetails?.details,
1185
- permission,
1186
- scope: JSON.stringify(scope),
1187
- category
1188
- }
1189
- });
1190
- return false;
1191
- }
1192
- const hasPermission = data === true;
1193
- rbacCache.set(cacheKey, hasPermission, 6e4);
1194
- const duration = Date.now() - startTime;
1195
- if (scope.organisationId) {
1196
- const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
1197
- await emitAuditEvent({
1198
- type: hasPermission ? "permission_check" : "permission_denied",
1199
- userId,
1200
- organisationId: scope.organisationId,
1201
- eventId: scope.eventId,
1202
- appId: scope.appId,
1203
- pageId: resolvedPageId,
1204
- permission,
1205
- decision: hasPermission,
1206
- source: "api",
1207
- duration_ms: duration,
1208
- cache_hit: cacheHit,
1209
- cache_source: cacheSource
1210
- });
1211
- }
1212
- return hasPermission;
1213
- } catch (error) {
1214
- const category = categorizeError(error);
1215
- const eventType = mapErrorCategoryToSecurityEventType(category);
1216
- const errorMessage = error instanceof Error ? error.message : "Unknown error";
1217
- RBACSecurityValidator.logSecurityEvent({
1218
- type: eventType,
1219
- userId,
1220
- details: {
1221
- error: errorMessage,
1222
- permission,
1223
- scope: JSON.stringify(scope),
1224
- category
1225
- }
1226
- });
1227
- const logger = getRBACLogger();
1228
- logger.error("Permission check failed:", error);
1229
- return false;
1230
- }
1231
- }
1232
- /**
1233
- * Get user's access level in a scope
1234
- *
1235
- * This is derived from roles, not permissions.
1236
- *
1237
- * @param input - Access level input
1238
- * @returns Promise resolving to access level
1239
- */
1240
- async getAccessLevel(input) {
1241
- const { userId, scope } = input;
1242
- const cacheKey = RBACCache.generateAccessLevelKey(
1243
- userId,
1244
- scope.organisationId || "",
1245
- scope.eventId,
1246
- scope.appId
1247
- );
1248
- const cached = rbacCache.get(cacheKey);
1249
- if (cached) {
1250
- return cached;
1251
- }
1252
- const now = (/* @__PURE__ */ new Date()).toISOString();
1253
- const isSuperAdmin2 = await this.checkSuperAdmin(userId);
1254
- if (isSuperAdmin2) {
1255
- rbacCache.set(cacheKey, "super", 6e4);
1256
- return "super";
1257
- }
1258
- if (scope.organisationId) {
1259
- const { data: orgRoles } = await this.supabase.from("rbac_organisation_roles").select("role").eq("user_id", userId).eq("organisation_id", scope.organisationId).eq("status", "active").is("revoked_at", null).lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).limit(1);
1260
- const orgRole = orgRoles?.[0];
1261
- if (orgRole?.role === "org_admin") {
1262
- rbacCache.set(cacheKey, "admin", 6e4);
1263
- return "admin";
1264
- }
1265
- }
1266
- if (scope.eventId && scope.appId) {
1267
- const { data: eventRole } = await this.supabase.from("rbac_event_app_roles").select("role").eq("user_id", userId).eq("event_id", scope.eventId).eq("app_id", scope.appId).eq("status", "active").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).single();
1268
- if (eventRole?.role === "event_admin") {
1269
- rbacCache.set(cacheKey, "admin", 6e4);
1270
- return "admin";
1271
- }
1272
- if (eventRole?.role === "planner") {
1273
- rbacCache.set(cacheKey, "planner", 6e4);
1274
- return "planner";
1275
- }
1276
- if (eventRole?.role === "participant") {
1277
- rbacCache.set(cacheKey, "participant", 6e4);
1278
- return "participant";
1279
- }
1280
- }
1281
- rbacCache.set(cacheKey, "viewer", 6e4);
1282
- return "viewer";
1283
- }
1284
- /**
1285
- * Get user's permission map for a scope
1286
- *
1287
- * This builds a map of page IDs to allowed operations.
1288
- * Uses the simplified RPC for each permission check.
1289
- *
1290
- * @param input - Permission map input
1291
- * @returns Promise resolving to permission map
1292
- */
1293
- async getPermissionMap(input) {
1294
- const { userId, scope } = input;
1295
- const cacheKey = RBACCache.generatePermissionMapKey(
1296
- userId,
1297
- scope.organisationId || "",
1298
- scope.eventId,
1299
- scope.appId
1300
- );
1301
- const isSuperAdmin2 = await this.checkSuperAdmin(userId);
1302
- if (isSuperAdmin2) {
1303
- const wildcardMap = { "*": true };
1304
- rbacCache.set(cacheKey, wildcardMap, 6e4);
1305
- return wildcardMap;
1306
- }
1307
- if (!scope.organisationId) {
1308
- return {};
1309
- }
1310
- const cached = rbacCache.get(cacheKey);
1311
- if (cached) {
1312
- return cached;
1313
- }
1314
- const permissionMap = {};
1315
- if (scope.appId) {
1316
- const { data: pages } = await this.supabase.from("rbac_app_pages").select("id, page_name").eq("app_id", scope.appId);
1317
- if (pages) {
1318
- if (!scope.organisationId) {
1319
- rbacCache.set(cacheKey, permissionMap, 6e4);
1320
- return permissionMap;
1321
- }
1322
- const securityContext = {
1323
- userId,
1324
- organisationId: scope.organisationId,
1325
- // Required
1326
- timestamp: /* @__PURE__ */ new Date()
1327
- };
1328
- for (const page of pages) {
1329
- for (const operation of ["read", "create", "update", "delete"]) {
1330
- const permissionString = `${operation}:page.${page.page_name}`;
1331
- const hasPermission = await this.isPermitted(
1332
- {
1333
- userId,
1334
- scope,
1335
- permission: permissionString,
1336
- pageId: page.id
1337
- },
1338
- securityContext
1339
- );
1340
- const permissionKey = permissionString;
1341
- permissionMap[permissionKey] = hasPermission;
1342
- }
1343
- }
1344
- }
1345
- }
1346
- rbacCache.set(cacheKey, permissionMap, 6e4);
1347
- return permissionMap;
1348
- }
1349
- async resolveAppContext(input) {
1350
- try {
1351
- const { userId, appName } = input;
1352
- const { data, error } = await this.supabase.rpc("data_app_resolve", {
1353
- p_user_id: userId,
1354
- p_app_name: appName
1355
- });
1356
- if (error) {
1357
- const logger = getRBACLogger();
1358
- logger.error("Failed to resolve app context:", error);
1359
- return null;
1360
- }
1361
- if (!data || data.length === 0) {
1362
- return null;
1363
- }
1364
- const appData = data[0];
1365
- if (!appData?.app_id) {
1366
- return null;
1367
- }
1368
- return {
1369
- appId: appData.app_id,
1370
- hasAccess: appData.has_access !== false
1371
- };
1372
- } catch (error) {
1373
- const logger = getRBACLogger();
1374
- logger.error("Unexpected error resolving app context:", error);
1375
- return null;
1376
- }
1377
- }
1378
- async getRoleContext(input) {
1379
- const result = {
1380
- globalRole: null,
1381
- organisationRole: null,
1382
- eventAppRole: null
1383
- };
1384
- try {
1385
- const { userId, scope } = input;
1386
- const { data, error } = await this.supabase.rpc("rbac_permissions_get", {
1387
- p_user_id: userId,
1388
- p_organisation_id: scope.organisationId || null,
1389
- p_event_id: scope.eventId || null,
1390
- p_app_id: scope.appId || null,
1391
- p_page_id: null
1392
- // Optional: can filter to specific page if needed
1393
- });
1394
- if (error) {
1395
- const logger = getRBACLogger();
1396
- logger.error("Failed to load role context:", error);
1397
- return result;
1398
- }
1399
- if (!Array.isArray(data)) {
1400
- return result;
1401
- }
1402
- for (const permission of data) {
1403
- if (permission.permission_type === "all_permissions") {
1404
- result.globalRole = "super_admin";
1405
- }
1406
- if (permission.permission_type === "organisation_access") {
1407
- result.organisationRole = permission.role_name;
1408
- }
1409
- if (permission.permission_type === "event_app_access") {
1410
- result.eventAppRole = permission.role_name;
1411
- }
1412
- }
1413
- return result;
1414
- } catch (error) {
1415
- const logger = getRBACLogger();
1416
- logger.error("Unexpected error loading role context:", error);
1417
- return result;
1418
- }
1419
- }
1420
- /**
1421
- * Check if user is super admin
1422
- *
1423
- * @param userId - User ID
1424
- * @returns Promise resolving to super admin status
1425
- */
1426
- async checkSuperAdmin(userId) {
1427
- const cacheKey = `super_admin:${userId}`;
1428
- const cached = rbacCache.get(cacheKey);
1429
- if (cached !== null) {
1430
- return cached;
1431
- }
1432
- const startTime = Date.now();
1433
- const now = (/* @__PURE__ */ new Date()).toISOString();
1434
- try {
1435
- const { data, error } = await this.supabase.from("rbac_global_roles").select("role").eq("user_id", userId).eq("role", "super_admin").lte("valid_from", now).or(`valid_to.is.null,valid_to.gte.${now}`).limit(1);
1436
- const elapsed = Date.now() - startTime;
1437
- if (elapsed > 2e3) {
1438
- console.warn("[RBACEngine] Super admin check took longer than expected", {
1439
- userId,
1440
- elapsedMs: elapsed,
1441
- error: error?.message
1442
- });
1443
- }
1444
- const isSuperAdmin2 = !error && data && data.length > 0;
1445
- rbacCache.set(cacheKey, isSuperAdmin2, 6e4);
1446
- return Boolean(isSuperAdmin2);
1447
- } catch (err) {
1448
- const elapsed = Date.now() - startTime;
1449
- console.error("[RBACEngine] Error checking super admin", {
1450
- userId,
1451
- error: err,
1452
- elapsedMs: elapsed
1453
- });
1454
- return false;
1455
- }
1456
- }
1457
- /**
1458
- * Resolve a page ID to UUID if it's a page name
1459
- *
1460
- * @param pageId - Page ID (UUID) or page name (string)
1461
- * @param appId - App ID to look up the page
1462
- * @returns Resolved page ID (UUID) or original pageId
1463
- */
1464
- async resolvePageId(pageId, appId) {
1465
- if (!pageId) {
1466
- return void 0;
1467
- }
1468
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1469
- if (uuidRegex.test(pageId)) {
1470
- return pageId;
1471
- }
1472
- if (!appId) {
1473
- return pageId;
1474
- }
1475
- try {
1476
- const { data: page, error: pageError } = await this.supabase.from("rbac_app_pages").select("id").eq("app_id", appId).eq("page_name", pageId).maybeSingle();
1477
- if (pageError) {
1478
- const logger = getRBACLogger();
1479
- if (pageError.code !== "PGRST116") {
1480
- logger.warn("Failed to resolve page name to UUID:", { pageId, appId, error: pageError });
1481
- }
1482
- return pageId;
1483
- }
1484
- return page?.id || pageId;
1485
- } catch (error) {
1486
- const logger = getRBACLogger();
1487
- logger.warn("Failed to resolve page name to UUID:", { pageId, appId, error });
1488
- return pageId;
1489
- }
1490
- }
1491
- };
1492
- function createRBACEngine(supabase, securityConfig) {
1493
- return new RBACEngine(supabase, securityConfig);
1494
- }
1495
-
1496
- // src/rbac/performance.ts
1497
- var RBACPerformanceMonitor = class {
1498
- constructor() {
1499
- this.metrics = {
1500
- totalChecks: 0,
1501
- cacheHits: 0,
1502
- cacheMisses: 0,
1503
- cacheHitRate: 0,
1504
- deduplicatedRequests: 0,
1505
- networkRequests: 0,
1506
- averageResponseTime: 0,
1507
- totalResponseTime: 0,
1508
- batchedAuditEvents: 0,
1509
- individualAuditEvents: 0
1510
- };
1511
- this.enabled = false;
1512
- }
1513
- /**
1514
- * Enable or disable performance monitoring
1515
- */
1516
- setEnabled(enabled) {
1517
- this.enabled = enabled;
1518
- }
1519
- /**
1520
- * Check if performance monitoring is enabled
1521
- */
1522
- isEnabled() {
1523
- return this.enabled;
1524
- }
1525
- /**
1526
- * Record a permission check
1527
- */
1528
- recordCheck(cacheHit, responseTime, wasDeduplicated = false) {
1529
- if (!this.enabled) {
1530
- return;
1531
- }
1532
- this.metrics.totalChecks++;
1533
- if (cacheHit) {
1534
- this.metrics.cacheHits++;
1535
- } else {
1536
- this.metrics.cacheMisses++;
1537
- this.metrics.networkRequests++;
1538
- }
1539
- if (wasDeduplicated) {
1540
- this.metrics.deduplicatedRequests++;
1541
- }
1542
- this.metrics.totalResponseTime += responseTime;
1543
- this.metrics.averageResponseTime = this.metrics.totalResponseTime / this.metrics.totalChecks;
1544
- this.metrics.cacheHitRate = this.metrics.cacheHits / this.metrics.totalChecks;
1545
- }
1546
- /**
1547
- * Record an audit event
1548
- */
1549
- recordAuditEvent(batched) {
1550
- if (!this.enabled) {
1551
- return;
1552
- }
1553
- if (batched) {
1554
- this.metrics.batchedAuditEvents++;
1555
- } else {
1556
- this.metrics.individualAuditEvents++;
1557
- }
1558
- }
1559
- /**
1560
- * Get current metrics
1561
- */
1562
- getMetrics() {
1563
- return { ...this.metrics };
1564
- }
1565
- /**
1566
- * Reset all metrics
1567
- */
1568
- reset() {
1569
- this.metrics = {
1570
- totalChecks: 0,
1571
- cacheHits: 0,
1572
- cacheMisses: 0,
1573
- cacheHitRate: 0,
1574
- deduplicatedRequests: 0,
1575
- networkRequests: 0,
1576
- averageResponseTime: 0,
1577
- totalResponseTime: 0,
1578
- batchedAuditEvents: 0,
1579
- individualAuditEvents: 0
1580
- };
1581
- }
1582
- /**
1583
- * Get metrics summary as a formatted string
1584
- */
1585
- getSummary() {
1586
- const m = this.metrics;
1587
- return `
1588
- RBAC Performance Metrics:
1589
- Total Checks: ${m.totalChecks}
1590
- Cache Hits: ${m.cacheHits} (${(m.cacheHitRate * 100).toFixed(1)}%)
1591
- Cache Misses: ${m.cacheMisses}
1592
- Deduplicated Requests: ${m.deduplicatedRequests}
1593
- Network Requests: ${m.networkRequests}
1594
- Average Response Time: ${m.averageResponseTime.toFixed(2)}ms
1595
- Batched Audit Events: ${m.batchedAuditEvents}
1596
- Individual Audit Events: ${m.individualAuditEvents}
1597
- `;
1598
- }
1599
- };
1600
- var performanceMonitor = new RBACPerformanceMonitor();
1601
- function enablePerformanceMonitoring() {
1602
- performanceMonitor.setEnabled(true);
1603
- }
1604
- function disablePerformanceMonitoring() {
1605
- performanceMonitor.setEnabled(false);
1606
- }
1607
- function isPerformanceMonitoringEnabled() {
1608
- return performanceMonitor.isEnabled();
1609
- }
1610
- function recordPermissionCheck(cacheHit, responseTime, wasDeduplicated = false) {
1611
- performanceMonitor.recordCheck(cacheHit, responseTime, wasDeduplicated);
1612
- }
1613
- function recordAuditEvent(batched) {
1614
- performanceMonitor.recordAuditEvent(batched);
1615
- }
1616
- function getPerformanceMetrics() {
1617
- return performanceMonitor.getMetrics();
1618
- }
1619
- function resetPerformanceMetrics() {
1620
- performanceMonitor.reset();
1621
- }
1622
- function getPerformanceSummary() {
1623
- return performanceMonitor.getSummary();
1624
- }
1625
-
1626
- // src/rbac/request-deduplication.ts
1627
- var inFlightRequests = /* @__PURE__ */ new Map();
1628
- function generateDeduplicationKey(input) {
1629
- return RBACCache.generatePermissionKey({
1630
- userId: input.userId,
1631
- organisationId: input.scope.organisationId,
1632
- // Can be undefined for page-level permissions
1633
- eventId: input.scope.eventId,
1634
- appId: input.scope.appId,
1635
- permission: input.permission,
1636
- pageId: input.pageId
1637
- });
1638
- }
1639
- async function getOrCreateRequest(input, checkFn) {
1640
- const key = generateDeduplicationKey(input);
1641
- const existingRequest = inFlightRequests.get(key);
1642
- if (existingRequest) {
1643
- return existingRequest;
1644
- }
1645
- const requestPromise = checkFn(input).finally(() => {
1646
- inFlightRequests.delete(key);
1647
- });
1648
- inFlightRequests.set(key, requestPromise);
1649
- return requestPromise;
1650
- }
1651
- function clearInFlightRequests() {
1652
- inFlightRequests.clear();
1653
- }
1654
- function getInFlightRequestCount() {
1655
- return inFlightRequests.size;
1656
- }
1657
-
1658
- // src/rbac/utils/eventContext.ts
1659
- var orgDerivationCache = /* @__PURE__ */ new Map();
1660
- var MAX_CACHE_SIZE = 100;
1661
- async function getOrganisationFromEvent(supabase, eventId) {
1662
- if (orgDerivationCache.has(eventId)) {
1663
- return orgDerivationCache.get(eventId) ?? null;
1664
- }
1665
- const { data, error } = await supabase.from("core_events").select("organisation_id").eq("event_id", eventId).single();
1666
- let organisationId = null;
1667
- if (error || !data) {
1668
- organisationId = null;
1669
- } else if (data.organisation_id) {
1670
- organisationId = data.organisation_id;
1671
- } else {
1672
- organisationId = null;
1673
- }
1674
- if (orgDerivationCache.size >= MAX_CACHE_SIZE) {
1675
- const firstKey = orgDerivationCache.keys().next().value;
1676
- if (firstKey) {
1677
- orgDerivationCache.delete(firstKey);
1678
- }
1679
- }
1680
- orgDerivationCache.set(eventId, organisationId);
1681
- return organisationId;
1682
- }
1683
-
1684
- // src/rbac/utils/contextValidator.ts
1685
- var log3 = createLogger("ContextValidator");
1686
- function allowsOptionalContexts(appName) {
1687
- return appName === "PORTAL" || appName === "ADMIN";
1688
- }
1689
- var ContextValidator = class {
1690
- /**
1691
- * Derive organisation ID from event ID
1692
- *
1693
- * @param supabase - Supabase client
1694
- * @param eventId - Event ID
1695
- * @returns Organisation ID or null
1696
- */
1697
- static async deriveOrgFromEvent(supabase, eventId) {
1698
- return getOrganisationFromEvent(supabase, eventId);
1699
- }
1700
- /**
1701
- * Resolve scope based on page-level scope_type
1702
- *
1703
- * This method handles page-level scoping. All pages have explicit scope_type set.
1704
- * Used for hybrid apps that have both event and organisation pages.
1705
- *
1706
- * @param scope - Current scope
1707
- * @param pageScopeType - Page scope type ('event', 'organisation', or 'both')
1708
- * @param appName - App name (for PORTAL/ADMIN special case)
1709
- * @param supabase - Supabase client (for deriving org from event, only if not already provided)
1710
- * @param immediateOrganisationId - Optional immediate organisation ID (from selectedEvent.organisation_id) - avoids querying
1711
- * @returns Resolved scope with all required context
1712
- */
1713
- static async resolveScopeForPage(scope, pageScopeType, appName, supabase, immediateOrganisationId) {
1714
- const effectiveScopeType = pageScopeType;
1715
- if (effectiveScopeType === "both") {
1716
- if (!scope.organisationId && !scope.eventId) {
1717
- if (allowsOptionalContexts(appName)) {
1718
- return {
1719
- isValid: true,
1720
- resolvedScope: {
1721
- organisationId: void 0,
1722
- eventId: void 0,
1723
- appId: scope.appId
1724
- },
1725
- error: null
1726
- };
1727
- }
1728
- return {
1729
- isValid: false,
1730
- resolvedScope: null,
1731
- error: new Error("Page requires either organisation or event context")
1732
- };
1733
- }
1734
- let organisationId = scope.organisationId || immediateOrganisationId || void 0;
1735
- if (!organisationId && scope.eventId && supabase) {
1736
- try {
1737
- const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
1738
- organisationId = derivedOrgId || void 0;
1739
- } catch (error) {
1740
- log3.warn("Failed to derive org from event for both-scope page:", error);
1741
- }
1742
- }
1743
- return {
1744
- isValid: true,
1745
- resolvedScope: {
1746
- organisationId,
1747
- eventId: scope.eventId,
1748
- appId: scope.appId
1749
- },
1750
- error: null
1751
- };
1752
- }
1753
- if (effectiveScopeType === "event") {
1754
- if (!scope.eventId) {
1755
- if (allowsOptionalContexts(appName)) {
1756
- return {
1757
- isValid: true,
1758
- resolvedScope: {
1759
- organisationId: scope.organisationId,
1760
- eventId: void 0,
1761
- appId: scope.appId
1762
- },
1763
- error: null
1764
- };
1765
- }
1766
- return {
1767
- isValid: false,
1768
- resolvedScope: null,
1769
- error: new EventContextRequiredError()
1770
- };
1771
- }
1772
- let organisationId = scope.organisationId || immediateOrganisationId || void 0;
1773
- if (!organisationId && supabase && scope.eventId) {
1774
- try {
1775
- const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
1776
- organisationId = derivedOrgId || void 0;
1777
- if (!organisationId) {
1778
- return {
1779
- isValid: false,
1780
- resolvedScope: null,
1781
- error: new Error("Could not resolve organisation from event context")
1782
- };
1783
- }
1784
- } catch (error) {
1785
- log3.error("Failed to derive org from event:", error);
1786
- return {
1787
- isValid: false,
1788
- resolvedScope: null,
1789
- error: error instanceof Error ? error : new Error("Failed to derive organisation from event")
1790
- };
1791
- }
1792
- }
1793
- return {
1794
- isValid: true,
1795
- resolvedScope: {
1796
- organisationId,
1797
- eventId: scope.eventId,
1798
- appId: scope.appId
1799
- },
1800
- error: null
1801
- };
1802
- }
1803
- if (effectiveScopeType === "organisation") {
1804
- if (!scope.organisationId) {
1805
- if (allowsOptionalContexts(appName)) {
1806
- return {
1807
- isValid: true,
1808
- resolvedScope: {
1809
- organisationId: void 0,
1810
- eventId: scope.eventId,
1811
- appId: scope.appId
1812
- },
1813
- error: null
1814
- };
1815
- }
1816
- return {
1817
- isValid: false,
1818
- resolvedScope: null,
1819
- error: new OrganisationContextRequiredError()
1820
- };
1821
- }
1822
- return {
1823
- isValid: true,
1824
- resolvedScope: {
1825
- organisationId: scope.organisationId,
1826
- eventId: scope.eventId,
1827
- // Event is optional for org-scoped pages
1828
- appId: scope.appId
1829
- },
1830
- error: null
1831
- };
1832
- }
1833
- return {
1834
- isValid: false,
1835
- resolvedScope: null,
1836
- error: new Error("Invalid scope type")
1837
- };
1838
- }
1839
- };
1840
-
1841
- // src/rbac/api.ts
1842
- var log4 = createLogger("RBACAPI");
1843
- var globalEngine = null;
1844
- function setupRBAC(supabase, config) {
1845
- getRBACLogger();
1846
- const isDevelopment = import.meta.env.MODE === "development";
1847
- const fullConfig = {
1848
- supabase,
1849
- debug: isDevelopment,
1850
- logLevel: "warn",
1851
- developmentMode: isDevelopment,
1852
- ...config
1853
- };
1854
- createRBACConfig(fullConfig);
1855
- const securityConfig = config === void 0 && !isDevelopment ? void 0 : {
1856
- // Default: disable rate limiting in development
1857
- ...isDevelopment && config?.security?.enableRateLimiting === void 0 ? { enableRateLimiting: false } : {},
1858
- // Explicit config overrides defaults
1859
- ...config?.security
1860
- };
1861
- globalEngine = createRBACEngine(supabase, securityConfig);
1862
- const useBatchedAudit = config?.audit?.batched !== false && config?.performance?.enableBatchedAuditLogging !== false;
1863
- const batchConfig = useBatchedAudit ? {
1864
- batchWindow: config?.audit?.batchWindow,
1865
- batchSize: config?.audit?.batchSize
1866
- } : void 0;
1867
- const auditManager = createAuditManager(supabase, useBatchedAudit, batchConfig);
1868
- setGlobalAuditManager(auditManager);
1869
- if (config?.performance?.enablePerformanceTracking) {
1870
- enablePerformanceMonitoring();
1871
- }
1872
- }
1873
- function isRBACInitialized() {
1874
- return globalEngine !== null;
1875
- }
1876
- function getEngine() {
1877
- if (!globalEngine) {
1878
- throw new RBACNotInitializedError();
1879
- }
1880
- return globalEngine;
1881
- }
1882
- async function getAccessLevel(input, appName) {
1883
- try {
1884
- const engine = getEngine();
1885
- const isSuperAdminUser = await engine["checkSuperAdmin"](input.userId);
1886
- if (isSuperAdminUser) {
1887
- return "super";
1888
- }
1889
- const validation = await ContextValidator.resolveScopeForPage(
1890
- input.scope,
1891
- "organisation",
1892
- // Default to organisation scope when no page context
1893
- appName,
1894
- engine["supabase"]
1895
- );
1896
- if (!validation.isValid || !validation.resolvedScope) {
1897
- throw validation.error || new OrganisationContextRequiredError();
1898
- }
1899
- return engine.getAccessLevel({
1900
- ...input,
1901
- scope: validation.resolvedScope
1902
- });
1903
- } catch (error) {
1904
- throw error;
1905
- }
1906
- }
1907
- async function getPermissionMap(input, appName) {
1908
- try {
1909
- const engine = getEngine();
1910
- const validation = await ContextValidator.resolveScopeForPage(
1911
- input.scope,
1912
- "organisation",
1913
- // Default to organisation scope when no page context
1914
- appName,
1915
- engine["supabase"]
1916
- );
1917
- if (!validation.isValid || !validation.resolvedScope) {
1918
- throw validation.error || new OrganisationContextRequiredError();
1919
- }
1920
- return engine.getPermissionMap({
1921
- ...input,
1922
- scope: validation.resolvedScope
1923
- });
1924
- } catch (error) {
1925
- throw error;
1926
- }
1927
- }
1928
- async function resolveAppContext(input) {
1929
- try {
1930
- const engine = getEngine();
1931
- return await engine.resolveAppContext(input);
1932
- } catch (error) {
1933
- throw error;
1934
- }
1935
- }
1936
- async function getRoleContext(input, appName) {
1937
- const engine = getEngine();
1938
- const validation = await ContextValidator.resolveScopeForPage(
1939
- input.scope,
1940
- "organisation",
1941
- // Default to organisation scope when no page context
1942
- appName,
1943
- engine["supabase"]
1944
- );
1945
- if (!validation.isValid || !validation.resolvedScope) {
1946
- throw validation.error || new OrganisationContextRequiredError();
1947
- }
1948
- return engine.getRoleContext({
1949
- ...input,
1950
- scope: validation.resolvedScope
1951
- });
1952
- }
1953
- async function isPermitted(input, appName, precomputedSuperAdmin = null) {
1954
- const engine = getEngine();
1955
- if (precomputedSuperAdmin === true) {
1956
- return true;
1957
- }
1958
- if (precomputedSuperAdmin === null) {
1959
- const isSuperAdminUser = await engine["checkSuperAdmin"](input.userId);
1960
- if (isSuperAdminUser) {
1961
- return true;
1962
- }
1963
- }
1964
- let resolvedAppName = appName;
1965
- if (!resolvedAppName && input.scope.appId) {
1966
- try {
1967
- const { data } = await engine["supabase"].from("rbac_apps").select("name").eq("id", input.scope.appId).eq("is_active", true).single();
1968
- if (data) {
1969
- resolvedAppName = data.name;
1970
- }
1971
- } catch (err) {
1972
- }
1973
- }
1974
- let pageScopeType;
1975
- if (input.pageId) {
1976
- try {
1977
- const scopeType = await getPageScopeType(
1978
- input.pageId,
1979
- input.scope.appId,
1980
- resolvedAppName
1981
- );
1982
- if (!scopeType) {
1983
- throw new Error(`Page ${input.pageId} does not have scope_type set`);
1984
- }
1985
- pageScopeType = scopeType;
1986
- } catch (err) {
1987
- log4.error("Failed to get page scope type:", err);
1988
- throw new Error(`Failed to determine page scope type: ${err instanceof Error ? err.message : String(err)}`);
1989
- }
1990
- } else {
1991
- pageScopeType = "organisation";
1992
- }
1993
- const validation = await ContextValidator.resolveScopeForPage(
1994
- input.scope,
1995
- pageScopeType,
1996
- resolvedAppName,
1997
- engine["supabase"]
1998
- );
1999
- if (!validation.isValid || !validation.resolvedScope) {
2000
- throw validation.error || new OrganisationContextRequiredError();
2001
- }
2002
- const validatedScope = validation.resolvedScope;
2003
- if (pageScopeType === "both" && input.pageId) {
2004
- const eventScope = {
2005
- organisationId: validatedScope.organisationId,
2006
- // Org derived from event
2007
- eventId: validatedScope.eventId,
2008
- appId: validatedScope.appId
2009
- };
2010
- const eventSecurityContext = {
2011
- userId: input.userId,
2012
- organisationId: eventScope.organisationId || null,
2013
- timestamp: /* @__PURE__ */ new Date()
2014
- };
2015
- const eventInput = {
2016
- ...input,
2017
- scope: eventScope
2018
- };
2019
- const hasEventPermission = await engine.isPermitted(eventInput, eventSecurityContext);
2020
- if (validatedScope.organisationId && validatedScope.eventId) {
2021
- const orgScope = {
2022
- organisationId: validatedScope.organisationId,
2023
- eventId: void 0,
2024
- // Clear event for org-only check
2025
- appId: validatedScope.appId
2026
- };
2027
- const orgSecurityContext = {
2028
- userId: input.userId,
2029
- organisationId: orgScope.organisationId || null,
2030
- timestamp: /* @__PURE__ */ new Date()
2031
- };
2032
- const orgInput = {
2033
- ...input,
2034
- scope: orgScope
2035
- };
2036
- const hasOrgPermission = await engine.isPermitted(orgInput, orgSecurityContext);
2037
- return hasEventPermission || hasOrgPermission;
2038
- }
2039
- return hasEventPermission;
2040
- }
2041
- const securityContext = {
2042
- userId: input.userId,
2043
- organisationId: validatedScope.organisationId || null,
2044
- timestamp: /* @__PURE__ */ new Date()
2045
- // Optional fields can be omitted
2046
- };
2047
- const validatedInput = {
2048
- ...input,
2049
- scope: validatedScope
2050
- };
2051
- return engine.isPermitted(validatedInput, securityContext);
2052
- }
2053
- async function isPermittedCached(input, appName) {
2054
- const { userId, scope, permission, pageId } = input;
2055
- const cacheKey = RBACCache.generatePermissionKey({
2056
- userId,
2057
- organisationId: scope.organisationId,
2058
- eventId: scope.eventId,
2059
- appId: scope.appId,
2060
- permission,
2061
- pageId
2062
- });
2063
- const cached = rbacCache.get(cacheKey, true);
2064
- if (cached !== null) {
2065
- return cached;
2066
- }
2067
- return getOrCreateRequest(input, async (checkInput) => {
2068
- const result = await isPermitted(checkInput, appName, null);
2069
- const isPageLevelCheck = !!pageId || permission.includes("page.");
2070
- rbacCache.set(cacheKey, result, void 0, isPageLevelCheck);
2071
- return result;
2072
- });
2073
- }
2074
- async function hasAnyPermission(input) {
2075
- const { permissions, ...baseInput } = input;
2076
- for (const permission of permissions) {
2077
- const hasPermission = await isPermitted({
2078
- ...baseInput,
2079
- permission
2080
- });
2081
- if (hasPermission) {
2082
- return true;
2083
- }
2084
- }
2085
- return false;
2086
- }
2087
- async function hasAllPermissions(input) {
2088
- const { permissions, ...baseInput } = input;
2089
- for (const permission of permissions) {
2090
- const hasPermission = await isPermitted({
2091
- ...baseInput,
2092
- permission
2093
- });
2094
- if (!hasPermission) {
2095
- return false;
2096
- }
2097
- }
2098
- return true;
2099
- }
2100
- async function isSuperAdmin(userId) {
2101
- const engine = getEngine();
2102
- return engine["checkSuperAdmin"](userId);
2103
- }
2104
- async function getPageScopeType(pageId, appId, appName) {
2105
- const engine = getEngine();
2106
- try {
2107
- let resolvedAppId = appId;
2108
- if (!resolvedAppId && appName) {
2109
- const { data: app } = await engine["supabase"].from("rbac_apps").select("id").eq("name", appName).eq("is_active", true).single();
2110
- resolvedAppId = app?.id;
2111
- }
2112
- if (!resolvedAppId) {
2113
- throw new Error(`Could not resolve appId for page ${pageId}`);
2114
- }
2115
- let resolvedPageId = pageId;
2116
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2117
- if (!uuidRegex.test(pageId)) {
2118
- const { data: page } = await engine["supabase"].from("rbac_app_pages").select("id").eq("app_id", resolvedAppId).eq("page_name", pageId).maybeSingle();
2119
- resolvedPageId = page?.id || pageId;
2120
- }
2121
- if (!uuidRegex.test(resolvedPageId)) {
2122
- throw new Error(`Could not resolve pageId ${pageId} to a valid UUID`);
2123
- }
2124
- const { data: pageData, error } = await engine["supabase"].from("rbac_app_pages").select("scope_type").eq("id", resolvedPageId).single();
2125
- if (error) {
2126
- log4.error("Error fetching page scope type:", { pageId, appId, error });
2127
- throw new Error(`Failed to get page scope type: ${error.message}`);
2128
- }
2129
- if (!pageData || !pageData.scope_type) {
2130
- throw new Error(`Page ${resolvedPageId} does not have scope_type set`);
2131
- }
2132
- return pageData.scope_type;
2133
- } catch (err) {
2134
- log4.error("Error fetching page scope type:", err);
2135
- throw err instanceof Error ? err : new Error(`Failed to get page scope type: ${String(err)}`);
2136
- }
2137
- }
2138
- async function isOrganisationAdmin(userId, organisationId) {
2139
- const accessLevel = await getAccessLevel({
2140
- userId,
2141
- scope: { organisationId }
2142
- });
2143
- return accessLevel === "admin" || accessLevel === "super";
2144
- }
2145
- async function isEventAdmin(userId, scope) {
2146
- if (!scope.eventId || !scope.appId) {
2147
- return false;
2148
- }
2149
- const accessLevel = await getAccessLevel({ userId, scope });
2150
- return accessLevel === "admin" || accessLevel === "super";
2151
- }
2152
- function invalidateUserCache(userId, organisationId) {
2153
- const patterns = organisationId ? [
2154
- CACHE_PATTERNS.PERMISSION(userId, organisationId),
2155
- `access:${userId}:${organisationId}:`,
2156
- `map:${userId}:${organisationId}:`
2157
- ] : [
2158
- `perm:${userId}:`,
2159
- `access:${userId}:`,
2160
- `map:${userId}:`
2161
- ];
2162
- patterns.forEach((pattern) => rbacCache.invalidate(pattern));
2163
- }
2164
- function invalidateOrganisationCache(organisationId) {
2165
- rbacCache.invalidate(CACHE_PATTERNS.ORGANISATION(organisationId));
2166
- }
2167
- function invalidateEventCache(eventId) {
2168
- rbacCache.invalidate(CACHE_PATTERNS.EVENT(eventId));
2169
- }
2170
- function invalidateAppCache(appId) {
2171
- rbacCache.invalidate(CACHE_PATTERNS.APP(appId));
2172
- }
2173
- function clearCache() {
2174
- rbacCache.clear();
2175
- }
2176
-
2177
- export { CACHE_PATTERNS, ContextValidator, EventContextRequiredError, OrganisationContextRequiredError, RBACCache, RBACEngine, RBACNotInitializedError, clearCache, clearInFlightRequests, createRBACConfig, createRBACEngine, disablePerformanceMonitoring, enablePerformanceMonitoring, getAccessLevel, getInFlightRequestCount, getPageScopeType, getPerformanceMetrics, getPerformanceSummary, getPermissionMap, getRBACConfig, getRBACLogger, getRoleContext, hasAllPermissions, hasAnyPermission, invalidateAppCache, invalidateEventCache, invalidateOrganisationCache, invalidateUserCache, isDebugMode, isDevelopmentMode, isEventAdmin, isOrganisationAdmin, isPerformanceMonitoringEnabled, isPermitted, isPermittedCached, isRBACInitialized, isSuperAdmin, rbacCache, recordAuditEvent, recordPermissionCheck, resetPerformanceMetrics, resolveAppContext, setupRBAC };