@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
@@ -0,0 +1,2321 @@
1
+ import { emitAuditEvent, createAuditManager, setGlobalAuditManager } from './chunk-QRYSEPHB.js';
2
+ import { createLogger } from './chunk-BTHN5MKC.js';
3
+ import { ok, err } from './chunk-44CNXN4P.js';
4
+
5
+ // src/rbac/types.ts
6
+ var RBACError = class extends Error {
7
+ constructor(message, code, context) {
8
+ super(message);
9
+ this.code = code;
10
+ this.context = context;
11
+ this.name = "RBACError";
12
+ }
13
+ };
14
+ var PermissionDeniedError = class extends RBACError {
15
+ constructor(permission, context) {
16
+ super(
17
+ `Permission denied: ${permission}`,
18
+ "PERMISSION_DENIED",
19
+ { permission, ...context }
20
+ );
21
+ this.name = "PermissionDeniedError";
22
+ }
23
+ };
24
+ var OrganisationContextRequiredError = class extends RBACError {
25
+ constructor() {
26
+ super(
27
+ "Organisation context is required for this operation",
28
+ "ORGANISATION_CONTEXT_REQUIRED"
29
+ );
30
+ this.name = "OrganisationContextRequiredError";
31
+ }
32
+ };
33
+ var EventContextRequiredError = class extends RBACError {
34
+ constructor() {
35
+ super(
36
+ "Event context is required for this operation",
37
+ "EVENT_CONTEXT_REQUIRED"
38
+ );
39
+ this.name = "EventContextRequiredError";
40
+ }
41
+ };
42
+ var RBACNotInitializedError = class extends RBACError {
43
+ constructor() {
44
+ super(
45
+ "RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup",
46
+ "RBAC_NOT_INITIALIZED"
47
+ );
48
+ this.name = "RBACNotInitializedError";
49
+ }
50
+ };
51
+ var InvalidScopeError = class extends RBACError {
52
+ constructor(scope, reason) {
53
+ super(
54
+ `Invalid scope provided: ${JSON.stringify(scope)}. ${reason}`,
55
+ "INVALID_SCOPE",
56
+ { scope, reason }
57
+ );
58
+ this.name = "InvalidScopeError";
59
+ }
60
+ };
61
+ var MissingUserContextError = class extends RBACError {
62
+ constructor() {
63
+ super(
64
+ "User context is required but not available. Make sure to wrap your app with an auth provider.",
65
+ "MISSING_USER_CONTEXT"
66
+ );
67
+ this.name = "MissingUserContextError";
68
+ }
69
+ };
70
+
71
+ // src/rbac/cache.ts
72
+ var RBACCache = class {
73
+ constructor() {
74
+ this.cache = /* @__PURE__ */ new Map();
75
+ this.sessionCache = /* @__PURE__ */ new Map();
76
+ this.TTL = 120 * 1e3;
77
+ // 120 seconds (short-term) - increased from 60s
78
+ this.SESSION_TTL = 15 * 60 * 1e3;
79
+ // 15 minutes (session-level) - increased from 5min
80
+ this.invalidationCallbacks = /* @__PURE__ */ new Set();
81
+ }
82
+ /**
83
+ * Get a value from the cache
84
+ *
85
+ * Checks both short-term cache and session cache.
86
+ *
87
+ * @param key - Cache key
88
+ * @param useSessionCache - Whether to check session cache (default: true)
89
+ * @returns Cached value or null if not found/expired
90
+ */
91
+ get(key, useSessionCache = true) {
92
+ const now = Date.now();
93
+ const entry = this.cache.get(key);
94
+ if (entry && now <= entry.expires) {
95
+ return entry.data;
96
+ }
97
+ if (entry && now > entry.expires) {
98
+ this.cache.delete(key);
99
+ }
100
+ if (useSessionCache) {
101
+ const sessionEntry = this.sessionCache.get(key);
102
+ if (sessionEntry && now <= sessionEntry.expires) {
103
+ return sessionEntry.data;
104
+ }
105
+ if (sessionEntry && now > sessionEntry.expires) {
106
+ this.sessionCache.delete(key);
107
+ }
108
+ }
109
+ return null;
110
+ }
111
+ /**
112
+ * Set a value in the cache
113
+ *
114
+ * @param key - Cache key
115
+ * @param data - Data to cache
116
+ * @param ttl - Time to live in milliseconds (defaults to 60s)
117
+ * @param useSessionCache - Whether to also store in session cache (default: false for page-level checks)
118
+ */
119
+ set(key, data, ttl = this.TTL, useSessionCache = false) {
120
+ const now = Date.now();
121
+ const expires = ttl <= 0 ? now - 1 : now + ttl;
122
+ this.cache.set(key, {
123
+ data,
124
+ expires
125
+ });
126
+ if (useSessionCache) {
127
+ const sessionExpires = ttl <= 0 ? now - 1 : now + this.SESSION_TTL;
128
+ this.sessionCache.set(key, {
129
+ data,
130
+ expires: sessionExpires
131
+ });
132
+ }
133
+ }
134
+ /**
135
+ * Delete a specific key from the cache
136
+ *
137
+ * @param key - Cache key to delete
138
+ */
139
+ delete(key) {
140
+ this.cache.delete(key);
141
+ this.sessionCache.delete(key);
142
+ }
143
+ /**
144
+ * Invalidate cache entries matching a pattern
145
+ *
146
+ * @param pattern - Pattern to match against cache keys
147
+ */
148
+ invalidate(pattern) {
149
+ const trimmedPattern = pattern?.trim();
150
+ if (!trimmedPattern) {
151
+ return;
152
+ }
153
+ const matcher = this.createMatcher(trimmedPattern);
154
+ const keysToDelete = [];
155
+ for (const key of this.cache.keys()) {
156
+ if (matcher(key)) {
157
+ keysToDelete.push(key);
158
+ }
159
+ }
160
+ for (const key of this.sessionCache.keys()) {
161
+ if (matcher(key) && !keysToDelete.includes(key)) {
162
+ keysToDelete.push(key);
163
+ }
164
+ }
165
+ keysToDelete.forEach((key) => {
166
+ this.cache.delete(key);
167
+ this.sessionCache.delete(key);
168
+ });
169
+ this.invalidationCallbacks.forEach((callback) => callback(trimmedPattern));
170
+ }
171
+ createMatcher(pattern) {
172
+ if (pattern.includes("*")) {
173
+ const escapedSegments = pattern.split("*").map((segment) => segment.replace(/[|\\{}()[\]^$+?.-]/g, "\\$&"));
174
+ const regexPattern = escapedSegments.join(".*");
175
+ const regex = new RegExp(regexPattern);
176
+ return (key) => regex.test(key);
177
+ }
178
+ return (key) => key.includes(pattern);
179
+ }
180
+ /**
181
+ * Clear all cache entries
182
+ */
183
+ clear() {
184
+ this.cache.clear();
185
+ this.sessionCache.clear();
186
+ }
187
+ /**
188
+ * Get cache statistics
189
+ */
190
+ getStats() {
191
+ return {
192
+ size: this.cache.size,
193
+ sessionSize: this.sessionCache.size,
194
+ ttl: this.TTL,
195
+ sessionTtl: this.SESSION_TTL,
196
+ keys: Array.from(this.cache.keys())
197
+ };
198
+ }
199
+ /**
200
+ * Add an invalidation callback
201
+ *
202
+ * @param callback - Function to call when cache is invalidated
203
+ */
204
+ onInvalidate(callback) {
205
+ this.invalidationCallbacks.add(callback);
206
+ return () => {
207
+ this.invalidationCallbacks.delete(callback);
208
+ };
209
+ }
210
+ /**
211
+ * Generate cache key for permission check (simplified signature)
212
+ *
213
+ * @param userId - User ID
214
+ * @param permission - Permission string
215
+ * @param organisationId - Organisation ID (optional)
216
+ * @param eventId - Event ID (optional)
217
+ * @param appId - App ID (optional)
218
+ * @param pageId - Page ID (optional)
219
+ * @returns String cache key
220
+ */
221
+ static generateKey(userId, permission, organisationId, eventId, appId, pageId) {
222
+ const parts = [
223
+ "perm",
224
+ userId,
225
+ organisationId || "null",
226
+ eventId || "null",
227
+ appId || "null",
228
+ permission || "null",
229
+ pageId || "null"
230
+ ];
231
+ return parts.join(":");
232
+ }
233
+ /**
234
+ * Generate cache key for permission check (object signature)
235
+ *
236
+ * @param key - Permission cache key object
237
+ * @returns String cache key
238
+ */
239
+ static generatePermissionKey(key) {
240
+ const parts = [
241
+ "perm",
242
+ key.userId,
243
+ key.organisationId || "null",
244
+ key.eventId || "null",
245
+ key.appId || "null",
246
+ key.permission || "null",
247
+ key.pageId || "null"
248
+ ];
249
+ return parts.join(":");
250
+ }
251
+ /**
252
+ * Generate cache key for access level
253
+ *
254
+ * @param userId - User ID
255
+ * @param organisationId - Organisation ID
256
+ * @param eventId - Event ID (optional)
257
+ * @param appId - App ID (optional)
258
+ * @returns String cache key
259
+ */
260
+ static generateAccessLevelKey(userId, organisationId, eventId, appId) {
261
+ const parts = [
262
+ "access",
263
+ userId,
264
+ organisationId,
265
+ eventId || "null",
266
+ appId || "null"
267
+ ];
268
+ return parts.join(":");
269
+ }
270
+ /**
271
+ * Generate cache key for permission map
272
+ *
273
+ * @param userId - User ID
274
+ * @param organisationId - Organisation ID
275
+ * @param eventId - Event ID (optional)
276
+ * @param appId - App ID (optional)
277
+ * @returns String cache key
278
+ */
279
+ static generatePermissionMapKey(userId, organisationId, eventId, appId) {
280
+ const parts = [
281
+ "map",
282
+ userId,
283
+ organisationId,
284
+ eventId || "null",
285
+ appId || "null"
286
+ ];
287
+ return parts.join(":");
288
+ }
289
+ };
290
+ var rbacCache = new RBACCache();
291
+ var CACHE_PATTERNS = {
292
+ USER: (userId) => `:${userId}:`,
293
+ ORGANISATION: (organisationId) => `:${organisationId}:`,
294
+ EVENT: (eventId) => `:${eventId}:`,
295
+ APP: (appId) => `:${appId}`,
296
+ PERMISSION: (userId, organisationId) => `perm:${userId}:${organisationId}:`
297
+ };
298
+
299
+ // src/rbac/cache-invalidation.ts
300
+ var log = createLogger("RBACCache");
301
+ var INVALIDATION_PATTERNS = {
302
+ // User-level invalidation
303
+ USER_ROLES_CHANGED: (userId) => [
304
+ CACHE_PATTERNS.USER(userId),
305
+ `perm:${userId}:*`,
306
+ `access:${userId}:*`,
307
+ `map:${userId}:*`
308
+ ],
309
+ // Organisation-level invalidation
310
+ ORGANISATION_PERMISSIONS_CHANGED: (organisationId) => [
311
+ CACHE_PATTERNS.ORGANISATION(organisationId),
312
+ `perm:*:${organisationId}:*`,
313
+ `access:*:${organisationId}:*`,
314
+ `map:*:${organisationId}:*`
315
+ ],
316
+ // Event-level invalidation
317
+ EVENT_PERMISSIONS_CHANGED: (eventId) => [
318
+ CACHE_PATTERNS.EVENT(eventId),
319
+ `perm:*:*:${eventId}:*`,
320
+ `access:*:*:${eventId}:*`,
321
+ `map:*:*:${eventId}:*`
322
+ ],
323
+ // App-level invalidation
324
+ APP_PERMISSIONS_CHANGED: (appId) => [
325
+ CACHE_PATTERNS.APP(appId),
326
+ `perm:*:*:*:${appId}:*`,
327
+ `access:*:*:*:${appId}`,
328
+ `map:*:*:*:${appId}`
329
+ ],
330
+ // Page-level invalidation
331
+ PAGE_PERMISSIONS_CHANGED: (pageId) => [
332
+ `perm:*:*:*:*:${pageId}`,
333
+ `map:*:*:*:*`
334
+ ]
335
+ };
336
+ var RBACCacheInvalidationManager = class {
337
+ constructor(supabase) {
338
+ this.invalidationCallbacks = /* @__PURE__ */ new Set();
339
+ this.channels = [];
340
+ this.supabase = supabase;
341
+ this.setupRealtimeSubscriptions();
342
+ }
343
+ /**
344
+ * Add a callback for cache invalidation events
345
+ *
346
+ * @param callback - Function to call when cache is invalidated
347
+ * @returns Unsubscribe function
348
+ */
349
+ onInvalidation(callback) {
350
+ this.invalidationCallbacks.add(callback);
351
+ return () => this.invalidationCallbacks.delete(callback);
352
+ }
353
+ /**
354
+ * Invalidate cache for a specific user
355
+ *
356
+ * @param userId - User ID
357
+ * @param reason - Reason for invalidation
358
+ */
359
+ invalidateUser(userId, reason) {
360
+ const patterns = INVALIDATION_PATTERNS.USER_ROLES_CHANGED(userId);
361
+ this.invalidatePatterns(patterns, reason);
362
+ }
363
+ /**
364
+ * Invalidate cache for a specific organisation
365
+ *
366
+ * @param organisationId - Organisation ID
367
+ * @param reason - Reason for invalidation
368
+ */
369
+ invalidateOrganisation(organisationId, reason) {
370
+ const patterns = INVALIDATION_PATTERNS.ORGANISATION_PERMISSIONS_CHANGED(organisationId);
371
+ this.invalidatePatterns(patterns, reason);
372
+ }
373
+ /**
374
+ * Invalidate cache for a specific event
375
+ *
376
+ * @param eventId - Event ID
377
+ * @param reason - Reason for invalidation
378
+ */
379
+ invalidateEvent(eventId, reason) {
380
+ const patterns = INVALIDATION_PATTERNS.EVENT_PERMISSIONS_CHANGED(eventId);
381
+ this.invalidatePatterns(patterns, reason);
382
+ }
383
+ /**
384
+ * Invalidate cache for a specific app
385
+ *
386
+ * @param appId - App ID
387
+ * @param reason - Reason for invalidation
388
+ */
389
+ invalidateApp(appId, reason) {
390
+ const patterns = INVALIDATION_PATTERNS.APP_PERMISSIONS_CHANGED(appId);
391
+ this.invalidatePatterns(patterns, reason);
392
+ }
393
+ /**
394
+ * Invalidate cache for a specific page
395
+ *
396
+ * @param pageId - Page ID
397
+ * @param reason - Reason for invalidation
398
+ */
399
+ invalidatePage(pageId, reason) {
400
+ const patterns = INVALIDATION_PATTERNS.PAGE_PERMISSIONS_CHANGED(pageId);
401
+ this.invalidatePatterns(patterns, reason);
402
+ }
403
+ /**
404
+ * Invalidate cache patterns and notify callbacks
405
+ *
406
+ * @param patterns - Array of cache patterns to invalidate
407
+ * @param reason - Reason for invalidation
408
+ */
409
+ invalidatePatterns(patterns, reason) {
410
+ log.debug(`Invalidating patterns: ${patterns.join(", ")} (${reason})`);
411
+ patterns.forEach((pattern) => {
412
+ rbacCache.invalidate(pattern);
413
+ });
414
+ this.invalidationCallbacks.forEach((callback) => {
415
+ patterns.forEach((pattern) => callback(pattern));
416
+ });
417
+ emitAuditEvent({
418
+ type: "permission_check",
419
+ userId: "system",
420
+ organisationId: "00000000-0000-0000-0000-000000000000",
421
+ permission: "cache:invalidate",
422
+ decision: true,
423
+ source: "api",
424
+ duration_ms: 0,
425
+ metadata: {
426
+ reason,
427
+ patterns,
428
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
429
+ cache_invalidation: true
430
+ }
431
+ }).catch((error) => {
432
+ log.warn("Failed to log cache invalidation audit event:", error);
433
+ });
434
+ }
435
+ /**
436
+ * Cleanup subscriptions only (not all callbacks)
437
+ * Used internally to cleanup before setting up new subscriptions
438
+ */
439
+ cleanupSubscriptions() {
440
+ this.channels.forEach((channel) => {
441
+ try {
442
+ if (channel && typeof channel.unsubscribe === "function") {
443
+ channel.unsubscribe();
444
+ }
445
+ } catch (error) {
446
+ log.warn("Failed to unsubscribe from channel:", error);
447
+ }
448
+ });
449
+ this.channels = [];
450
+ }
451
+ /**
452
+ * Setup realtime subscriptions for automatic cache invalidation
453
+ * Always cleans up existing subscriptions before setting up new ones to prevent duplicates
454
+ */
455
+ setupRealtimeSubscriptions() {
456
+ this.cleanupSubscriptions();
457
+ if (!this.supabase.channel || typeof this.supabase.channel !== "function") {
458
+ log.debug("Realtime not available, skipping subscriptions");
459
+ return;
460
+ }
461
+ const orgRolesChannel = this.supabase.channel("rbac_organisation_roles_changes").on("postgres_changes", {
462
+ event: "*",
463
+ schema: "public",
464
+ table: "rbac_organisation_roles"
465
+ }, (payload) => {
466
+ const payloadData = payload;
467
+ const { organisation_id, user_id } = payloadData.new || payloadData.old || {};
468
+ if (organisation_id) {
469
+ this.invalidateOrganisation(organisation_id, `organisation_role_${payloadData.eventType || "unknown"}`);
470
+ }
471
+ if (user_id) {
472
+ this.invalidateUser(user_id, `organisation_role_${payloadData.eventType || "unknown"}`);
473
+ }
474
+ });
475
+ const orgRolesSubscription = orgRolesChannel.subscribe();
476
+ this.channels.push(orgRolesSubscription);
477
+ const eventAppRolesChannel = this.supabase.channel("rbac_event_app_roles_changes").on("postgres_changes", {
478
+ event: "*",
479
+ schema: "public",
480
+ table: "rbac_event_app_roles"
481
+ }, (payload) => {
482
+ const payloadData = payload;
483
+ const { organisation_id, user_id, event_id, app_id } = payloadData.new || payloadData.old || {};
484
+ if (organisation_id) {
485
+ this.invalidateOrganisation(organisation_id, `event_app_role_${payloadData.eventType || "unknown"}`);
486
+ }
487
+ if (user_id) {
488
+ this.invalidateUser(user_id, `event_app_role_${payloadData.eventType || "unknown"}`);
489
+ }
490
+ if (event_id) {
491
+ this.invalidateEvent(event_id, `event_app_role_${payloadData.eventType || "unknown"}`);
492
+ }
493
+ if (app_id) {
494
+ this.invalidateApp(app_id, `event_app_role_${payloadData.eventType || "unknown"}`);
495
+ }
496
+ });
497
+ const eventAppRolesSubscription = eventAppRolesChannel.subscribe();
498
+ this.channels.push(eventAppRolesSubscription);
499
+ const globalRolesChannel = this.supabase.channel("rbac_global_roles_changes").on("postgres_changes", {
500
+ event: "*",
501
+ schema: "public",
502
+ table: "rbac_global_roles"
503
+ }, (payload) => {
504
+ const payloadData = payload;
505
+ const { user_id } = payloadData.new || payloadData.old || {};
506
+ if (user_id) {
507
+ this.invalidateUser(user_id, `global_role_${payloadData.eventType || "unknown"}`);
508
+ }
509
+ });
510
+ const globalRolesSubscription = globalRolesChannel.subscribe();
511
+ this.channels.push(globalRolesSubscription);
512
+ const pagePermissionsChannel = this.supabase.channel("rbac_page_permissions_changes").on("postgres_changes", {
513
+ event: "*",
514
+ schema: "public",
515
+ table: "rbac_page_permissions"
516
+ }, (payload) => {
517
+ const { organisation_id, app_page_id } = payload.new || payload.old || {};
518
+ if (organisation_id) {
519
+ this.invalidateOrganisation(organisation_id, `page_permission_${payload.eventType}`);
520
+ }
521
+ if (app_page_id) {
522
+ this.invalidatePage(app_page_id, `page_permission_${payload.eventType}`);
523
+ }
524
+ });
525
+ const pagePermissionsSubscription = pagePermissionsChannel.subscribe();
526
+ this.channels.push(pagePermissionsSubscription);
527
+ }
528
+ /**
529
+ * Cleanup all realtime subscriptions
530
+ * Call this when the manager is no longer needed to prevent memory leaks
531
+ */
532
+ cleanup() {
533
+ this.channels.forEach((channel) => {
534
+ try {
535
+ if (channel && typeof channel.unsubscribe === "function") {
536
+ channel.unsubscribe();
537
+ }
538
+ } catch (error) {
539
+ log.warn("Failed to unsubscribe from channel:", error);
540
+ }
541
+ });
542
+ this.channels = [];
543
+ this.invalidationCallbacks.clear();
544
+ }
545
+ /**
546
+ * Manually trigger cache invalidation for all users in an organisation
547
+ *
548
+ * @param organisationId - Organisation ID
549
+ * @param reason - Reason for invalidation
550
+ */
551
+ async invalidateAllUsersInOrganisation(organisationId, reason) {
552
+ const { data: users } = await this.supabase.from("rbac_organisation_roles").select("user_id").eq("organisation_id", organisationId).eq("is_active", true);
553
+ if (users) {
554
+ users.forEach(({ user_id }) => {
555
+ this.invalidateUser(user_id, reason);
556
+ });
557
+ }
558
+ }
559
+ /**
560
+ * Clear all cache entries
561
+ */
562
+ clearAllCache() {
563
+ log.debug("Clearing all cache entries");
564
+ rbacCache.clear();
565
+ }
566
+ };
567
+ var globalCacheInvalidationManager = null;
568
+ function initializeCacheInvalidation(supabase) {
569
+ if (globalCacheInvalidationManager) {
570
+ globalCacheInvalidationManager.cleanup();
571
+ }
572
+ globalCacheInvalidationManager = new RBACCacheInvalidationManager(supabase);
573
+ return globalCacheInvalidationManager;
574
+ }
575
+
576
+ // src/rbac/errors.ts
577
+ var RATE_LIMIT_STATUS_CODES = /* @__PURE__ */ new Set([429]);
578
+ var AUTH_STATUS_CODES = /* @__PURE__ */ new Set([401]);
579
+ var AUTHZ_STATUS_CODES = /* @__PURE__ */ new Set([403]);
580
+ function normalize(value) {
581
+ if (!value) {
582
+ return "";
583
+ }
584
+ if (typeof value === "string") {
585
+ return value.toLowerCase();
586
+ }
587
+ if (value instanceof Error && typeof value.message === "string") {
588
+ return value.message.toLowerCase();
589
+ }
590
+ return String(value).toLowerCase();
591
+ }
592
+ function categorizeByErrorClass(error) {
593
+ if (error instanceof PermissionDeniedError) {
594
+ return "authorization_error" /* AUTHORIZATION */;
595
+ }
596
+ if (error instanceof OrganisationContextRequiredError || error instanceof InvalidScopeError) {
597
+ return "validation_error" /* VALIDATION */;
598
+ }
599
+ if (error instanceof MissingUserContextError) {
600
+ return "authentication_error" /* AUTHENTICATION */;
601
+ }
602
+ return null;
603
+ }
604
+ function categorizeByRBACErrorCode(error) {
605
+ if (!(error instanceof RBACError)) {
606
+ return null;
607
+ }
608
+ switch (error.code) {
609
+ case "PERMISSION_DENIED":
610
+ return "authorization_error" /* AUTHORIZATION */;
611
+ case "ORGANISATION_CONTEXT_REQUIRED":
612
+ case "INVALID_SCOPE":
613
+ return "validation_error" /* VALIDATION */;
614
+ case "MISSING_USER_CONTEXT":
615
+ return "authentication_error" /* AUTHENTICATION */;
616
+ default:
617
+ return null;
618
+ }
619
+ }
620
+ function categorizeByHttpStatus(error) {
621
+ if (!error || typeof error !== "object") {
622
+ return null;
623
+ }
624
+ const status = error.status;
625
+ if (typeof status !== "number") {
626
+ return null;
627
+ }
628
+ if (RATE_LIMIT_STATUS_CODES.has(status)) {
629
+ return "rate_limit_error" /* RATE_LIMIT */;
630
+ }
631
+ if (AUTH_STATUS_CODES.has(status)) {
632
+ return "authentication_error" /* AUTHENTICATION */;
633
+ }
634
+ if (AUTHZ_STATUS_CODES.has(status)) {
635
+ return "authorization_error" /* AUTHORIZATION */;
636
+ }
637
+ if (status >= 500) {
638
+ return "database_error" /* DATABASE */;
639
+ }
640
+ return null;
641
+ }
642
+ function categorizeByCodeString(error) {
643
+ if (!error || typeof error !== "object") {
644
+ return null;
645
+ }
646
+ const codeValue = normalize(error.code);
647
+ if (!codeValue) {
648
+ return null;
649
+ }
650
+ if (codeValue.includes("network")) {
651
+ return "network_error" /* NETWORK */;
652
+ }
653
+ if (codeValue.includes("postgres") || codeValue.includes("database") || codeValue.includes("db")) {
654
+ return "database_error" /* DATABASE */;
655
+ }
656
+ if (codeValue.includes("rate")) {
657
+ return "rate_limit_error" /* RATE_LIMIT */;
658
+ }
659
+ if (codeValue.includes("auth")) {
660
+ return "authentication_error" /* AUTHENTICATION */;
661
+ }
662
+ if (codeValue.includes("permission")) {
663
+ return "authorization_error" /* AUTHORIZATION */;
664
+ }
665
+ if (codeValue.includes("scope") || codeValue.includes("invalid")) {
666
+ return "validation_error" /* VALIDATION */;
667
+ }
668
+ return null;
669
+ }
670
+ function categorizeByMessage(error) {
671
+ const message = normalize(error);
672
+ if (message.includes("timeout") || message.includes("network") || message.includes("fetch")) {
673
+ return "network_error" /* NETWORK */;
674
+ }
675
+ if (message.includes("postgres") || message.includes("database") || message.includes("connection")) {
676
+ return "database_error" /* DATABASE */;
677
+ }
678
+ if (message.includes("rate limit") || message.includes("too many requests")) {
679
+ return "rate_limit_error" /* RATE_LIMIT */;
680
+ }
681
+ if (message.includes("permission") || message.includes("forbidden")) {
682
+ return "authorization_error" /* AUTHORIZATION */;
683
+ }
684
+ if (message.includes("auth") || message.includes("token") || message.includes("session")) {
685
+ return "authentication_error" /* AUTHENTICATION */;
686
+ }
687
+ if (message.includes("invalid") || message.includes("scope") || message.includes("validation")) {
688
+ return "validation_error" /* VALIDATION */;
689
+ }
690
+ return null;
691
+ }
692
+ function categorizeError(error) {
693
+ const byClass = categorizeByErrorClass(error);
694
+ if (byClass !== null) return byClass;
695
+ const byCode = categorizeByRBACErrorCode(error);
696
+ if (byCode !== null) return byCode;
697
+ const byStatus = categorizeByHttpStatus(error);
698
+ if (byStatus !== null) return byStatus;
699
+ const byCodeString = categorizeByCodeString(error);
700
+ if (byCodeString !== null) return byCodeString;
701
+ const byMessage = categorizeByMessage(error);
702
+ if (byMessage !== null) return byMessage;
703
+ return "unknown_error" /* UNKNOWN */;
704
+ }
705
+ function mapErrorCategoryToSecurityEventType(category) {
706
+ switch (category) {
707
+ case "authorization_error" /* AUTHORIZATION */:
708
+ return "permission_denied";
709
+ case "network_error" /* NETWORK */:
710
+ return "network_error";
711
+ case "database_error" /* DATABASE */:
712
+ return "database_error";
713
+ case "validation_error" /* VALIDATION */:
714
+ return "validation_error";
715
+ case "rate_limit_error" /* RATE_LIMIT */:
716
+ return "rate_limit_error";
717
+ case "authentication_error" /* AUTHENTICATION */:
718
+ return "authentication_error";
719
+ case "unknown_error" /* UNKNOWN */:
720
+ default:
721
+ return "unknown_error";
722
+ }
723
+ }
724
+
725
+ // src/rbac/security.ts
726
+ var log2 = createLogger("RBACSecurity");
727
+ var RBACSecurityValidator = class {
728
+ /**
729
+ * Validate permission string format
730
+ * @param permission - Permission string to validate
731
+ * @returns True if valid, false otherwise
732
+ */
733
+ static validatePermission(permission) {
734
+ if (typeof permission !== "string" || permission.length === 0) {
735
+ return false;
736
+ }
737
+ const permissionRegex = /^(read|create|update|delete):[a-z0-9._-]+$/;
738
+ return permissionRegex.test(permission);
739
+ }
740
+ /**
741
+ * Validate UUID format
742
+ * @param uuid - UUID string to validate
743
+ * @returns True if valid, false otherwise
744
+ */
745
+ static validateUUID(uuid) {
746
+ if (typeof uuid !== "string" || uuid.length === 0) {
747
+ return false;
748
+ }
749
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
750
+ return uuidRegex.test(uuid);
751
+ }
752
+ /**
753
+ * Validate scope object
754
+ * @param scope - Scope object to validate
755
+ * @returns True if valid, false otherwise
756
+ */
757
+ static validateScope(scope) {
758
+ if (!scope || typeof scope !== "object") {
759
+ return false;
760
+ }
761
+ if (scope.organisationId !== void 0) {
762
+ if (typeof scope.organisationId === "string" && scope.organisationId.trim() === "") {
763
+ return false;
764
+ }
765
+ if (scope.organisationId && !this.validateUUID(scope.organisationId)) {
766
+ return false;
767
+ }
768
+ }
769
+ if (scope.eventId && typeof scope.eventId !== "string") {
770
+ return false;
771
+ }
772
+ if (scope.appId && !this.validateUUID(scope.appId)) {
773
+ return false;
774
+ }
775
+ return !!(scope.organisationId || scope.eventId || scope.appId);
776
+ }
777
+ /**
778
+ * Sanitize input string to prevent injection attacks
779
+ * @param input - Input string to sanitize
780
+ * @returns Sanitized string
781
+ */
782
+ static sanitizeInput(input) {
783
+ if (typeof input !== "string") {
784
+ return "";
785
+ }
786
+ return input.replace(/<[^>]*>/g, "").replace(/[<>\"'&]/g, "").replace(/[;()]/g, "").replace(/javascript:/gi, "").replace(/data:/gi, "").trim();
787
+ }
788
+ /**
789
+ * Validate user ID format
790
+ * @param userId - User ID to validate
791
+ * @returns True if valid, false otherwise
792
+ */
793
+ static validateUserId(userId) {
794
+ return this.validateUUID(userId);
795
+ }
796
+ /**
797
+ * Check if permission is a wildcard permission
798
+ * @param permission - Permission string to check
799
+ * @returns True if wildcard, false otherwise
800
+ */
801
+ static isWildcardPermission(permission) {
802
+ return permission.includes("*") || permission.endsWith(":*");
803
+ }
804
+ /**
805
+ * Validate permission hierarchy
806
+ * @param permission - Permission to validate
807
+ * @param requiredOperation - Required operation
808
+ * @returns True if permission matches or is higher in hierarchy
809
+ */
810
+ static validatePermissionHierarchy(permission, requiredOperation) {
811
+ if (!this.validatePermission(permission)) {
812
+ return false;
813
+ }
814
+ const [operation] = permission.split(":");
815
+ const hierarchy = ["read", "create", "update", "delete"];
816
+ const permissionLevel = hierarchy.indexOf(operation);
817
+ const requiredLevel = hierarchy.indexOf(requiredOperation);
818
+ if (permissionLevel === -1 || requiredLevel === -1) {
819
+ return false;
820
+ }
821
+ return permissionLevel >= requiredLevel;
822
+ }
823
+ /**
824
+ * Rate limiting check (placeholder for future implementation)
825
+ * @param userId - User ID
826
+ * @param operation - Operation being performed
827
+ * @returns True if within rate limit, false otherwise
828
+ */
829
+ static async checkRateLimit(_userId, _operation) {
830
+ return true;
831
+ }
832
+ // Only warn once per 5 seconds per user
833
+ static logSecurityEvent(event) {
834
+ const securityEvent = {
835
+ ...event,
836
+ timestamp: event.timestamp || /* @__PURE__ */ new Date(),
837
+ severity: this.getEventSeverity(event.type)
838
+ };
839
+ if (event.type === "rate_limit_exceeded") {
840
+ const now = Date.now();
841
+ const userWarning = this.rateLimitWarningCount.get(event.userId);
842
+ if (userWarning) {
843
+ const timeSinceLastWarning = now - userWarning.lastWarning;
844
+ if (timeSinceLastWarning < this.RATE_LIMIT_WARNING_THROTTLE_MS) {
845
+ userWarning.count++;
846
+ this.rateLimitWarningCount.set(event.userId, userWarning);
847
+ return;
848
+ } else {
849
+ log2.warn("Security event (throttled):", {
850
+ ...securityEvent,
851
+ details: {
852
+ ...securityEvent.details,
853
+ suppressedWarnings: userWarning.count,
854
+ message: `Rate limit exceeded (${userWarning.count + 1} times in last ${Math.round(timeSinceLastWarning / 1e3)}s)`
855
+ }
856
+ });
857
+ this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });
858
+ return;
859
+ }
860
+ } else {
861
+ this.rateLimitWarningCount.set(event.userId, { count: 0, lastWarning: now });
862
+ log2.warn("Security event:", securityEvent);
863
+ return;
864
+ }
865
+ }
866
+ log2.warn("Security event:", securityEvent);
867
+ }
868
+ /**
869
+ * Get severity level for security event
870
+ * @param eventType - Type of security event
871
+ * @returns Severity level
872
+ */
873
+ static getEventSeverity(eventType) {
874
+ switch (eventType) {
875
+ case "permission_denied":
876
+ return "low";
877
+ case "invalid_input":
878
+ case "rate_limit_exceeded":
879
+ case "rate_limit_error":
880
+ case "network_error":
881
+ return "medium";
882
+ case "validation_error":
883
+ return "high";
884
+ case "authentication_error":
885
+ case "database_error":
886
+ return "critical";
887
+ case "suspicious_activity":
888
+ case "unknown_error":
889
+ return "high";
890
+ default:
891
+ return "low";
892
+ }
893
+ }
894
+ };
895
+ /**
896
+ * Log security event for monitoring
897
+ * @param event - Security event details
898
+ */
899
+ RBACSecurityValidator.rateLimitWarningCount = /* @__PURE__ */ new Map();
900
+ RBACSecurityValidator.RATE_LIMIT_WARNING_THROTTLE_MS = 5e3;
901
+ var DEFAULT_SECURITY_CONFIG = {
902
+ enableInputValidation: true,
903
+ enableRateLimiting: true,
904
+ enableAuditLogging: true,
905
+ maxPermissionChecksPerMinute: 1e3,
906
+ // Increased from 100 to 1000 for normal app usage
907
+ suspiciousActivityThreshold: 10
908
+ };
909
+ var RBACSecurityMiddleware = class {
910
+ constructor(config = DEFAULT_SECURITY_CONFIG) {
911
+ /**
912
+ * In-memory rate limiting cache (sliding window)
913
+ * Note: For production, this should use Redis or Supabase Edge Functions
914
+ */
915
+ this.rateLimitCache = /* @__PURE__ */ new Map();
916
+ this.config = config;
917
+ this._startCleanupInterval();
918
+ }
919
+ /**
920
+ * Start periodic cleanup of expired entries
921
+ */
922
+ _startCleanupInterval() {
923
+ setInterval(() => {
924
+ this.clearExpiredEntries();
925
+ }, 5 * 60 * 1e3);
926
+ }
927
+ /**
928
+ * Validate input before processing
929
+ * @param input - Input to validate
930
+ * @param context - Security context
931
+ * @returns Validation result
932
+ */
933
+ async validateInput(input, context) {
934
+ const errors = [];
935
+ if (!RBACSecurityValidator.validateUserId(context.userId)) {
936
+ errors.push("Invalid user ID format");
937
+ }
938
+ const permission = typeof input.permission === "string" ? input.permission : "";
939
+ const isPagePermission = permission.includes(":page.") || !!input.pageId;
940
+ const requiresOrgId = !isPagePermission;
941
+ if (requiresOrgId) {
942
+ if (!context.organisationId) {
943
+ errors.push("Organisation ID is required for resource-level permissions");
944
+ } else if (!RBACSecurityValidator.validateUUID(context.organisationId)) {
945
+ errors.push("Invalid organisation ID format");
946
+ }
947
+ } else {
948
+ if (context.organisationId && !RBACSecurityValidator.validateUUID(context.organisationId)) {
949
+ errors.push("Invalid organisation ID format");
950
+ }
951
+ }
952
+ if (permission && !RBACSecurityValidator.validatePermission(permission)) {
953
+ errors.push("Invalid permission format");
954
+ }
955
+ if (input.scope && !RBACSecurityValidator.validateScope(input.scope)) {
956
+ errors.push("Invalid scope format");
957
+ }
958
+ if (this.config.enableInputValidation) {
959
+ if (context.ipAddress && typeof context.ipAddress !== "string") {
960
+ errors.push("Invalid IP address format");
961
+ }
962
+ if (context.userAgent && typeof context.userAgent !== "string") {
963
+ errors.push("Invalid user agent format");
964
+ }
965
+ }
966
+ if (errors.length > 0) {
967
+ RBACSecurityValidator.logSecurityEvent({
968
+ type: "invalid_input",
969
+ userId: context.userId,
970
+ details: { errors, input: this.sanitizeInput(JSON.stringify(input)) }
971
+ });
972
+ }
973
+ return {
974
+ isValid: errors.length === 0,
975
+ errors
976
+ };
977
+ }
978
+ /**
979
+ * Check rate limiting
980
+ * @param context - Security context
981
+ * @returns Rate limit check result
982
+ */
983
+ async checkRateLimit(context) {
984
+ if (!this.config.enableRateLimiting) {
985
+ return { isAllowed: true, remaining: this.config.maxPermissionChecksPerMinute };
986
+ }
987
+ const isAllowed = await this._checkRateLimitInternal(context.userId);
988
+ const remaining = isAllowed ? this.config.maxPermissionChecksPerMinute - this._getRequestCount(context.userId) : 0;
989
+ return {
990
+ isAllowed,
991
+ remaining: Math.max(0, remaining)
992
+ };
993
+ }
994
+ async _checkRateLimitInternal(userId) {
995
+ const now = Date.now();
996
+ const windowMs = 60 * 1e3;
997
+ const entries = this.rateLimitCache.get(userId) || [];
998
+ const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
999
+ const requestCount = validEntries.length;
1000
+ const isAllowed = requestCount < this.config.maxPermissionChecksPerMinute;
1001
+ if (isAllowed) {
1002
+ validEntries.push({ timestamp: now });
1003
+ }
1004
+ this.rateLimitCache.set(userId, validEntries);
1005
+ return isAllowed;
1006
+ }
1007
+ _getRequestCount(userId) {
1008
+ const now = Date.now();
1009
+ const windowMs = 60 * 1e3;
1010
+ const entries = this.rateLimitCache.get(userId) || [];
1011
+ const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
1012
+ return validEntries.length;
1013
+ }
1014
+ /**
1015
+ * Clear old rate limit entries to prevent memory leaks
1016
+ * Should be called periodically (e.g., every 5 minutes)
1017
+ */
1018
+ clearExpiredEntries() {
1019
+ const now = Date.now();
1020
+ const windowMs = 60 * 1e3;
1021
+ for (const [userId, entries] of this.rateLimitCache.entries()) {
1022
+ const validEntries = entries.filter((entry) => now - entry.timestamp < windowMs);
1023
+ if (validEntries.length === 0) {
1024
+ this.rateLimitCache.delete(userId);
1025
+ } else {
1026
+ this.rateLimitCache.set(userId, validEntries);
1027
+ }
1028
+ }
1029
+ }
1030
+ /**
1031
+ * Sanitize input data
1032
+ * @param input - Input to sanitize
1033
+ * @returns Sanitized input
1034
+ */
1035
+ sanitizeInput(input) {
1036
+ return RBACSecurityValidator.sanitizeInput(input);
1037
+ }
1038
+ };
1039
+
1040
+ // src/rbac/config.ts
1041
+ var logger = createLogger("RBAC");
1042
+ var RBACConfigManager = class {
1043
+ constructor() {
1044
+ this.config = null;
1045
+ this.logger = null;
1046
+ }
1047
+ setConfig(config) {
1048
+ this.config = config;
1049
+ this.setupLogger();
1050
+ }
1051
+ getConfig() {
1052
+ return this.config;
1053
+ }
1054
+ getLogger() {
1055
+ if (!this.logger) {
1056
+ this.logger = this.createDefaultLogger();
1057
+ }
1058
+ return this.logger;
1059
+ }
1060
+ setupLogger() {
1061
+ if (!this.config) return;
1062
+ const { debug = false, logLevel = "warn" } = this.config;
1063
+ this.logger = {
1064
+ error: (message, ...args) => {
1065
+ logger.error(message, ...args);
1066
+ },
1067
+ warn: (message, ...args) => {
1068
+ if (logLevel === "warn" || logLevel === "info" || logLevel === "debug") {
1069
+ logger.warn(message, ...args);
1070
+ }
1071
+ },
1072
+ info: (message, ...args) => {
1073
+ if (logLevel === "info" || logLevel === "debug") {
1074
+ logger.info(message, ...args);
1075
+ }
1076
+ },
1077
+ debug: (message, ...args) => {
1078
+ if (debug && logLevel === "debug") {
1079
+ logger.debug(message, ...args);
1080
+ }
1081
+ }
1082
+ };
1083
+ }
1084
+ createDefaultLogger() {
1085
+ return {
1086
+ error: (message, ...args) => logger.error(message, ...args),
1087
+ warn: (message, ...args) => logger.warn(message, ...args),
1088
+ info: (message, ...args) => logger.info(message, ...args),
1089
+ debug: (message, ...args) => logger.debug(message, ...args)
1090
+ };
1091
+ }
1092
+ isDebugMode() {
1093
+ return this.config?.debug ?? false;
1094
+ }
1095
+ isDevelopmentMode() {
1096
+ return this.config?.developmentMode ?? false;
1097
+ }
1098
+ getMockPermissions() {
1099
+ return this.config?.mockPermissions ?? null;
1100
+ }
1101
+ };
1102
+ var configManager = new RBACConfigManager();
1103
+ function createRBACConfig(config) {
1104
+ configManager.setConfig(config);
1105
+ return config;
1106
+ }
1107
+ function getRBACConfig() {
1108
+ return configManager.getConfig();
1109
+ }
1110
+ function getRBACLogger() {
1111
+ return configManager.getLogger();
1112
+ }
1113
+ function isDebugMode() {
1114
+ return configManager.isDebugMode();
1115
+ }
1116
+ function isDevelopmentMode() {
1117
+ return configManager.isDevelopmentMode();
1118
+ }
1119
+
1120
+ // src/rbac/engine.ts
1121
+ var RBACEngine = class {
1122
+ constructor(supabase, securityConfig) {
1123
+ this.supabase = supabase;
1124
+ const mergedSecurityConfig = {
1125
+ ...DEFAULT_SECURITY_CONFIG,
1126
+ ...securityConfig
1127
+ };
1128
+ this.securityMiddleware = new RBACSecurityMiddleware(mergedSecurityConfig);
1129
+ initializeCacheInvalidation(supabase);
1130
+ }
1131
+ /**
1132
+ * Check if a user has a specific permission
1133
+ *
1134
+ * This method now delegates to the database RPC function for all the heavy lifting.
1135
+ *
1136
+ * @param input - Permission check input
1137
+ * @param securityContext - Security context for validation (required)
1138
+ * @returns Promise resolving to permission result
1139
+ */
1140
+ async isPermitted(input, securityContext) {
1141
+ const startTime = Date.now();
1142
+ const { userId, permission, scope, pageId } = input;
1143
+ let cacheHit = false;
1144
+ let cacheSource = "rpc";
1145
+ try {
1146
+ const validation = await this.securityMiddleware.validateInput(input, securityContext);
1147
+ if (!validation.isValid) {
1148
+ RBACSecurityValidator.logSecurityEvent({
1149
+ type: "invalid_input",
1150
+ userId,
1151
+ details: { errors: validation.errors, input: JSON.stringify(input) }
1152
+ });
1153
+ return false;
1154
+ }
1155
+ const rateLimit = await this.securityMiddleware.checkRateLimit(securityContext);
1156
+ if (!rateLimit.isAllowed) {
1157
+ RBACSecurityValidator.logSecurityEvent({
1158
+ type: "rate_limit_exceeded",
1159
+ userId,
1160
+ details: { remaining: rateLimit.remaining }
1161
+ });
1162
+ return false;
1163
+ }
1164
+ if (!RBACSecurityValidator.validateUserId(userId)) {
1165
+ RBACSecurityValidator.logSecurityEvent({
1166
+ type: "invalid_input",
1167
+ userId,
1168
+ details: { error: "Invalid user ID format" }
1169
+ });
1170
+ return false;
1171
+ }
1172
+ if (!RBACSecurityValidator.validatePermission(permission)) {
1173
+ RBACSecurityValidator.logSecurityEvent({
1174
+ type: "invalid_input",
1175
+ userId,
1176
+ details: { error: "Invalid permission format", permission }
1177
+ });
1178
+ return false;
1179
+ }
1180
+ if (!RBACSecurityValidator.validateScope(scope)) {
1181
+ RBACSecurityValidator.logSecurityEvent({
1182
+ type: "invalid_input",
1183
+ userId,
1184
+ details: { error: "Invalid scope format", scope }
1185
+ });
1186
+ return false;
1187
+ }
1188
+ const cacheKey = RBACCache.generateKey(
1189
+ userId,
1190
+ permission,
1191
+ scope.organisationId,
1192
+ scope.eventId,
1193
+ scope.appId,
1194
+ pageId
1195
+ );
1196
+ const cached = rbacCache.get(cacheKey);
1197
+ if (cached !== null) {
1198
+ cacheHit = true;
1199
+ cacheSource = "memory";
1200
+ return cached;
1201
+ }
1202
+ const { data, error } = await this.supabase.rpc("rbac_check_permission_simplified", {
1203
+ p_user_id: userId,
1204
+ p_permission: permission,
1205
+ p_organisation_id: scope.organisationId || void 0,
1206
+ p_event_id: scope.eventId || void 0,
1207
+ p_app_id: scope.appId || void 0,
1208
+ p_page_id: pageId || void 0
1209
+ });
1210
+ if (error) {
1211
+ const logger2 = getRBACLogger();
1212
+ logger2.error("RPC error:", error);
1213
+ const category = categorizeError(error);
1214
+ const eventType = mapErrorCategoryToSecurityEventType(category);
1215
+ const errorDetails = error;
1216
+ RBACSecurityValidator.logSecurityEvent({
1217
+ type: eventType,
1218
+ userId,
1219
+ details: {
1220
+ error: errorDetails?.message || "RPC call failed",
1221
+ code: errorDetails?.code,
1222
+ hint: errorDetails?.hint,
1223
+ details: errorDetails?.details,
1224
+ permission,
1225
+ scope: JSON.stringify(scope),
1226
+ category
1227
+ }
1228
+ });
1229
+ return false;
1230
+ }
1231
+ const hasPermission = data === true;
1232
+ rbacCache.set(cacheKey, hasPermission, 6e4);
1233
+ const duration = Date.now() - startTime;
1234
+ if (scope.organisationId) {
1235
+ const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
1236
+ await emitAuditEvent({
1237
+ type: hasPermission ? "permission_check" : "permission_denied",
1238
+ userId,
1239
+ organisationId: scope.organisationId,
1240
+ eventId: scope.eventId,
1241
+ appId: scope.appId,
1242
+ pageId: resolvedPageId,
1243
+ permission,
1244
+ decision: hasPermission,
1245
+ source: "api",
1246
+ duration_ms: duration,
1247
+ cache_hit: cacheHit,
1248
+ cache_source: cacheSource
1249
+ });
1250
+ }
1251
+ return hasPermission;
1252
+ } catch (error) {
1253
+ const category = categorizeError(error);
1254
+ const eventType = mapErrorCategoryToSecurityEventType(category);
1255
+ const errorMessage = error instanceof Error ? error.message : "Unknown error";
1256
+ RBACSecurityValidator.logSecurityEvent({
1257
+ type: eventType,
1258
+ userId,
1259
+ details: {
1260
+ error: errorMessage,
1261
+ permission,
1262
+ scope: JSON.stringify(scope),
1263
+ category
1264
+ }
1265
+ });
1266
+ const logger2 = getRBACLogger();
1267
+ logger2.error("Permission check failed:", error);
1268
+ return false;
1269
+ }
1270
+ }
1271
+ /**
1272
+ * Get user's access level in a scope
1273
+ *
1274
+ * This is derived from roles, not permissions.
1275
+ *
1276
+ * @param input - Access level input
1277
+ * @returns Promise resolving to access level
1278
+ */
1279
+ async getAccessLevel(input) {
1280
+ const { userId, scope } = input;
1281
+ const cacheKey = RBACCache.generateAccessLevelKey(
1282
+ userId,
1283
+ scope.organisationId || "",
1284
+ scope.eventId,
1285
+ scope.appId
1286
+ );
1287
+ const cached = rbacCache.get(cacheKey);
1288
+ if (cached) {
1289
+ return cached;
1290
+ }
1291
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1292
+ const isSuperAdmin2 = await this.checkSuperAdmin(userId);
1293
+ if (isSuperAdmin2) {
1294
+ rbacCache.set(cacheKey, "super", 6e4);
1295
+ return "super";
1296
+ }
1297
+ if (scope.organisationId) {
1298
+ 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);
1299
+ const orgRole = orgRoles?.[0];
1300
+ if (orgRole?.role === "org_admin") {
1301
+ rbacCache.set(cacheKey, "admin", 6e4);
1302
+ return "admin";
1303
+ }
1304
+ }
1305
+ if (scope.eventId && scope.appId) {
1306
+ 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();
1307
+ if (eventRole?.role === "event_admin") {
1308
+ rbacCache.set(cacheKey, "admin", 6e4);
1309
+ return "admin";
1310
+ }
1311
+ if (eventRole?.role === "planner") {
1312
+ rbacCache.set(cacheKey, "planner", 6e4);
1313
+ return "planner";
1314
+ }
1315
+ if (eventRole?.role === "participant") {
1316
+ rbacCache.set(cacheKey, "participant", 6e4);
1317
+ return "participant";
1318
+ }
1319
+ }
1320
+ rbacCache.set(cacheKey, "viewer", 6e4);
1321
+ return "viewer";
1322
+ }
1323
+ /**
1324
+ * Get user's permission map for a scope
1325
+ *
1326
+ * This builds a map of page IDs to allowed operations.
1327
+ * Uses the simplified RPC for each permission check.
1328
+ *
1329
+ * @param input - Permission map input
1330
+ * @returns Promise resolving to permission map
1331
+ */
1332
+ async getPermissionMap(input) {
1333
+ const { userId, scope } = input;
1334
+ const cacheKey = RBACCache.generatePermissionMapKey(
1335
+ userId,
1336
+ scope.organisationId || "",
1337
+ scope.eventId,
1338
+ scope.appId
1339
+ );
1340
+ const isSuperAdmin2 = await this.checkSuperAdmin(userId);
1341
+ if (isSuperAdmin2) {
1342
+ const wildcardMap = { "*": true };
1343
+ rbacCache.set(cacheKey, wildcardMap, 6e4);
1344
+ return wildcardMap;
1345
+ }
1346
+ if (!scope.organisationId) {
1347
+ return {};
1348
+ }
1349
+ const cached = rbacCache.get(cacheKey);
1350
+ if (cached) {
1351
+ return cached;
1352
+ }
1353
+ const permissionMap = {};
1354
+ if (scope.appId) {
1355
+ const { data: pages } = await this.supabase.from("rbac_app_pages").select("id, page_name").eq("app_id", scope.appId);
1356
+ if (pages) {
1357
+ if (!scope.organisationId) {
1358
+ rbacCache.set(cacheKey, permissionMap, 6e4);
1359
+ return permissionMap;
1360
+ }
1361
+ const securityContext = {
1362
+ userId,
1363
+ organisationId: scope.organisationId,
1364
+ // Required
1365
+ timestamp: /* @__PURE__ */ new Date()
1366
+ };
1367
+ for (const page of pages) {
1368
+ for (const operation of ["read", "create", "update", "delete"]) {
1369
+ const permissionString = `${operation}:page.${page.page_name}`;
1370
+ const hasPermission = await this.isPermitted(
1371
+ {
1372
+ userId,
1373
+ scope,
1374
+ permission: permissionString,
1375
+ pageId: page.id
1376
+ },
1377
+ securityContext
1378
+ );
1379
+ const permissionKey = permissionString;
1380
+ permissionMap[permissionKey] = hasPermission;
1381
+ }
1382
+ }
1383
+ }
1384
+ }
1385
+ rbacCache.set(cacheKey, permissionMap, 6e4);
1386
+ return permissionMap;
1387
+ }
1388
+ async resolveAppContext(input) {
1389
+ try {
1390
+ const { userId, appName } = input;
1391
+ const { data, error } = await this.supabase.rpc("data_app_resolve", {
1392
+ p_user_id: userId,
1393
+ p_app_name: appName
1394
+ });
1395
+ if (error) {
1396
+ const logger2 = getRBACLogger();
1397
+ logger2.error("Failed to resolve app context:", error);
1398
+ return null;
1399
+ }
1400
+ if (!data || !Array.isArray(data) || data.length === 0) {
1401
+ return null;
1402
+ }
1403
+ const appData = data[0];
1404
+ if (!appData?.app_id) {
1405
+ return null;
1406
+ }
1407
+ return {
1408
+ appId: appData.app_id,
1409
+ hasAccess: appData.has_access !== false
1410
+ };
1411
+ } catch (error) {
1412
+ const logger2 = getRBACLogger();
1413
+ logger2.error("Unexpected error resolving app context:", error);
1414
+ return null;
1415
+ }
1416
+ }
1417
+ async getRoleContext(input) {
1418
+ const result = {
1419
+ globalRole: null,
1420
+ organisationRole: null,
1421
+ eventAppRole: null
1422
+ };
1423
+ try {
1424
+ const { userId, scope } = input;
1425
+ const { data, error } = await this.supabase.rpc("rbac_permissions_get", {
1426
+ p_user_id: userId,
1427
+ p_organisation_id: scope.organisationId || null,
1428
+ p_event_id: scope.eventId || null,
1429
+ p_app_id: scope.appId || null,
1430
+ p_page_id: null
1431
+ // Optional: can filter to specific page if needed
1432
+ });
1433
+ if (error) {
1434
+ const logger2 = getRBACLogger();
1435
+ logger2.error("Failed to load role context:", error);
1436
+ return result;
1437
+ }
1438
+ if (!Array.isArray(data)) {
1439
+ return result;
1440
+ }
1441
+ const mapToOrganisationRole = (level) => {
1442
+ switch (level) {
1443
+ case "supporter":
1444
+ return "supporter";
1445
+ case "member":
1446
+ return "member";
1447
+ case "leader":
1448
+ return "leader";
1449
+ case "org_admin":
1450
+ case "admin":
1451
+ case "super":
1452
+ return "org_admin";
1453
+ default:
1454
+ return null;
1455
+ }
1456
+ };
1457
+ const mapToEventAppRole = (level) => {
1458
+ switch (level) {
1459
+ case "viewer":
1460
+ return "viewer";
1461
+ case "participant":
1462
+ return "participant";
1463
+ case "planner":
1464
+ return "planner";
1465
+ case "admin":
1466
+ case "super":
1467
+ return "event_admin";
1468
+ default:
1469
+ return null;
1470
+ }
1471
+ };
1472
+ for (const permission of data) {
1473
+ if (permission.permission_type === "all_permissions") {
1474
+ result.globalRole = "super_admin";
1475
+ }
1476
+ if (permission.permission_type === "organisation_access") {
1477
+ result.organisationRole = mapToOrganisationRole(permission.role_name);
1478
+ }
1479
+ if (permission.permission_type === "event_app_access") {
1480
+ result.eventAppRole = mapToEventAppRole(permission.role_name);
1481
+ }
1482
+ }
1483
+ return result;
1484
+ } catch (error) {
1485
+ const logger2 = getRBACLogger();
1486
+ logger2.error("Unexpected error loading role context:", error);
1487
+ return result;
1488
+ }
1489
+ }
1490
+ /**
1491
+ * Check if user is super admin
1492
+ *
1493
+ * @param userId - User ID
1494
+ * @returns Promise resolving to super admin status
1495
+ */
1496
+ async checkSuperAdmin(userId) {
1497
+ const cacheKey = `super_admin:${userId}`;
1498
+ const cached = rbacCache.get(cacheKey);
1499
+ if (cached !== null) {
1500
+ return cached;
1501
+ }
1502
+ const startTime = Date.now();
1503
+ const now = (/* @__PURE__ */ new Date()).toISOString();
1504
+ try {
1505
+ 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);
1506
+ const elapsed = Date.now() - startTime;
1507
+ if (elapsed > 2e3) {
1508
+ const logger2 = getRBACLogger();
1509
+ const errorMessage = error && typeof error === "object" && "message" in error ? String(error.message) : void 0;
1510
+ logger2.warn("[RBACEngine] Super admin check took longer than expected", {
1511
+ userId,
1512
+ elapsedMs: elapsed,
1513
+ error: errorMessage
1514
+ });
1515
+ }
1516
+ const isSuperAdmin2 = !error && data && data.length > 0;
1517
+ rbacCache.set(cacheKey, isSuperAdmin2, 6e4);
1518
+ return Boolean(isSuperAdmin2);
1519
+ } catch (err2) {
1520
+ const elapsed = Date.now() - startTime;
1521
+ const logger2 = getRBACLogger();
1522
+ logger2.error("[RBACEngine] Error checking super admin", {
1523
+ userId,
1524
+ error: err2,
1525
+ elapsedMs: elapsed
1526
+ });
1527
+ return false;
1528
+ }
1529
+ }
1530
+ /**
1531
+ * Resolve a page ID to UUID if it's a page name
1532
+ *
1533
+ * @param pageId - Page ID (UUID) or page name (string)
1534
+ * @param appId - App ID to look up the page
1535
+ * @returns Resolved page ID (UUID) or original pageId
1536
+ */
1537
+ async resolvePageId(pageId, appId) {
1538
+ if (!pageId) {
1539
+ return void 0;
1540
+ }
1541
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1542
+ if (uuidRegex.test(pageId)) {
1543
+ return pageId;
1544
+ }
1545
+ if (!appId) {
1546
+ return pageId;
1547
+ }
1548
+ try {
1549
+ const { data: page, error: pageError } = await this.supabase.from("rbac_app_pages").select("id").eq("app_id", appId).eq("page_name", pageId).maybeSingle();
1550
+ if (pageError) {
1551
+ const logger2 = getRBACLogger();
1552
+ if (pageError.code !== "PGRST116") {
1553
+ logger2.warn("Failed to resolve page name to UUID:", { pageId, appId, error: pageError });
1554
+ }
1555
+ return pageId;
1556
+ }
1557
+ return page?.id || pageId;
1558
+ } catch (error) {
1559
+ const logger2 = getRBACLogger();
1560
+ logger2.warn("Failed to resolve page name to UUID:", { pageId, appId, error });
1561
+ return pageId;
1562
+ }
1563
+ }
1564
+ };
1565
+ function createRBACEngine(supabase, securityConfig) {
1566
+ return new RBACEngine(supabase, securityConfig);
1567
+ }
1568
+
1569
+ // src/rbac/performance.ts
1570
+ var RBACPerformanceMonitor = class {
1571
+ constructor() {
1572
+ this.metrics = {
1573
+ totalChecks: 0,
1574
+ cacheHits: 0,
1575
+ cacheMisses: 0,
1576
+ cacheHitRate: 0,
1577
+ deduplicatedRequests: 0,
1578
+ networkRequests: 0,
1579
+ averageResponseTime: 0,
1580
+ totalResponseTime: 0,
1581
+ batchedAuditEvents: 0,
1582
+ individualAuditEvents: 0
1583
+ };
1584
+ this.enabled = false;
1585
+ }
1586
+ /**
1587
+ * Enable or disable performance monitoring
1588
+ */
1589
+ setEnabled(enabled) {
1590
+ this.enabled = enabled;
1591
+ }
1592
+ /**
1593
+ * Check if performance monitoring is enabled
1594
+ */
1595
+ isEnabled() {
1596
+ return this.enabled;
1597
+ }
1598
+ /**
1599
+ * Record a permission check
1600
+ */
1601
+ recordCheck(cacheHit, responseTime, wasDeduplicated = false) {
1602
+ if (!this.enabled) {
1603
+ return;
1604
+ }
1605
+ this.metrics.totalChecks++;
1606
+ if (cacheHit) {
1607
+ this.metrics.cacheHits++;
1608
+ } else {
1609
+ this.metrics.cacheMisses++;
1610
+ this.metrics.networkRequests++;
1611
+ }
1612
+ if (wasDeduplicated) {
1613
+ this.metrics.deduplicatedRequests++;
1614
+ }
1615
+ this.metrics.totalResponseTime += responseTime;
1616
+ this.metrics.averageResponseTime = this.metrics.totalResponseTime / this.metrics.totalChecks;
1617
+ this.metrics.cacheHitRate = this.metrics.cacheHits / this.metrics.totalChecks;
1618
+ }
1619
+ /**
1620
+ * Record an audit event
1621
+ */
1622
+ recordAuditEvent(batched) {
1623
+ if (!this.enabled) {
1624
+ return;
1625
+ }
1626
+ if (batched) {
1627
+ this.metrics.batchedAuditEvents++;
1628
+ } else {
1629
+ this.metrics.individualAuditEvents++;
1630
+ }
1631
+ }
1632
+ /**
1633
+ * Get current metrics
1634
+ */
1635
+ getMetrics() {
1636
+ return { ...this.metrics };
1637
+ }
1638
+ /**
1639
+ * Reset all metrics
1640
+ */
1641
+ reset() {
1642
+ this.metrics = {
1643
+ totalChecks: 0,
1644
+ cacheHits: 0,
1645
+ cacheMisses: 0,
1646
+ cacheHitRate: 0,
1647
+ deduplicatedRequests: 0,
1648
+ networkRequests: 0,
1649
+ averageResponseTime: 0,
1650
+ totalResponseTime: 0,
1651
+ batchedAuditEvents: 0,
1652
+ individualAuditEvents: 0
1653
+ };
1654
+ }
1655
+ /**
1656
+ * Get metrics summary as a formatted string
1657
+ */
1658
+ getSummary() {
1659
+ const m = this.metrics;
1660
+ return `
1661
+ RBAC Performance Metrics:
1662
+ Total Checks: ${m.totalChecks}
1663
+ Cache Hits: ${m.cacheHits} (${(m.cacheHitRate * 100).toFixed(1)}%)
1664
+ Cache Misses: ${m.cacheMisses}
1665
+ Deduplicated Requests: ${m.deduplicatedRequests}
1666
+ Network Requests: ${m.networkRequests}
1667
+ Average Response Time: ${m.averageResponseTime.toFixed(2)}ms
1668
+ Batched Audit Events: ${m.batchedAuditEvents}
1669
+ Individual Audit Events: ${m.individualAuditEvents}
1670
+ `;
1671
+ }
1672
+ };
1673
+ var performanceMonitor = new RBACPerformanceMonitor();
1674
+ function enablePerformanceMonitoring() {
1675
+ performanceMonitor.setEnabled(true);
1676
+ }
1677
+ function disablePerformanceMonitoring() {
1678
+ performanceMonitor.setEnabled(false);
1679
+ }
1680
+ function isPerformanceMonitoringEnabled() {
1681
+ return performanceMonitor.isEnabled();
1682
+ }
1683
+ function recordPermissionCheck(cacheHit, responseTime, wasDeduplicated = false) {
1684
+ performanceMonitor.recordCheck(cacheHit, responseTime, wasDeduplicated);
1685
+ }
1686
+ function recordAuditEvent(batched) {
1687
+ performanceMonitor.recordAuditEvent(batched);
1688
+ }
1689
+ function getPerformanceMetrics() {
1690
+ return performanceMonitor.getMetrics();
1691
+ }
1692
+ function resetPerformanceMetrics() {
1693
+ performanceMonitor.reset();
1694
+ }
1695
+ function getPerformanceSummary() {
1696
+ return performanceMonitor.getSummary();
1697
+ }
1698
+
1699
+ // src/rbac/request-deduplication.ts
1700
+ var inFlightRequests = /* @__PURE__ */ new Map();
1701
+ function generateDeduplicationKey(input) {
1702
+ return RBACCache.generatePermissionKey({
1703
+ userId: input.userId,
1704
+ organisationId: input.scope.organisationId,
1705
+ // Can be undefined for page-level permissions
1706
+ eventId: input.scope.eventId,
1707
+ appId: input.scope.appId,
1708
+ permission: input.permission,
1709
+ pageId: input.pageId
1710
+ });
1711
+ }
1712
+ async function getOrCreateRequest(input, checkFn) {
1713
+ const key = generateDeduplicationKey(input);
1714
+ const existingRequest = inFlightRequests.get(key);
1715
+ if (existingRequest) {
1716
+ return existingRequest;
1717
+ }
1718
+ const requestPromise = checkFn(input).finally(() => {
1719
+ inFlightRequests.delete(key);
1720
+ });
1721
+ inFlightRequests.set(key, requestPromise);
1722
+ return requestPromise;
1723
+ }
1724
+ function clearInFlightRequests() {
1725
+ inFlightRequests.clear();
1726
+ }
1727
+ function getInFlightRequestCount() {
1728
+ return inFlightRequests.size;
1729
+ }
1730
+
1731
+ // src/rbac/utils/eventContext.ts
1732
+ var orgDerivationCache = /* @__PURE__ */ new Map();
1733
+ var MAX_CACHE_SIZE = 100;
1734
+ async function getOrganisationFromEvent(supabase, eventId) {
1735
+ if (orgDerivationCache.has(eventId)) {
1736
+ return ok(orgDerivationCache.get(eventId) ?? null);
1737
+ }
1738
+ try {
1739
+ const { data, error } = await supabase.from("core_events").select("organisation_id").eq("event_id", eventId).single();
1740
+ let organisationId = null;
1741
+ if (error) {
1742
+ return err({ code: "ORG_FROM_EVENT_FAILED", message: error.message ?? "Failed to get organisation from event" });
1743
+ }
1744
+ if (data?.organisation_id) {
1745
+ organisationId = data.organisation_id;
1746
+ }
1747
+ if (orgDerivationCache.size >= MAX_CACHE_SIZE) {
1748
+ const firstKey = orgDerivationCache.keys().next().value;
1749
+ if (firstKey) {
1750
+ orgDerivationCache.delete(firstKey);
1751
+ }
1752
+ }
1753
+ orgDerivationCache.set(eventId, organisationId);
1754
+ return ok(organisationId);
1755
+ } catch (e) {
1756
+ return err({ code: "ORG_FROM_EVENT_FAILED", message: e instanceof Error ? e.message : String(e) });
1757
+ }
1758
+ }
1759
+
1760
+ // src/rbac/utils/contextValidator.ts
1761
+ var log3 = createLogger("ContextValidator");
1762
+ function allowsOptionalContexts(appName) {
1763
+ return appName === "PORTAL" || appName === "ADMIN";
1764
+ }
1765
+ var ContextValidator = class {
1766
+ /**
1767
+ * Derive organisation ID from event ID
1768
+ *
1769
+ * @param supabase - Supabase client
1770
+ * @param eventId - Event ID
1771
+ * @returns Organisation ID or null
1772
+ */
1773
+ static async deriveOrgFromEvent(supabase, eventId) {
1774
+ const result = await getOrganisationFromEvent(supabase, eventId);
1775
+ if (!result.ok) {
1776
+ return null;
1777
+ }
1778
+ return result.data;
1779
+ }
1780
+ /**
1781
+ * Resolve scope based on page-level scope_type
1782
+ *
1783
+ * This method handles page-level scoping. All pages have explicit scope_type set.
1784
+ * Used for hybrid apps that have both event and organisation pages.
1785
+ *
1786
+ * @param scope - Current scope
1787
+ * @param pageScopeType - Page scope type ('event', 'organisation', or 'both')
1788
+ * @param appName - App name (for PORTAL/ADMIN special case)
1789
+ * @param supabase - Supabase client (for deriving org from event, only if not already provided)
1790
+ * @param immediateOrganisationId - Optional immediate organisation ID (from selectedEvent.organisation_id) - avoids querying
1791
+ * @returns Resolved scope with all required context
1792
+ */
1793
+ static async resolveScopeForPage(scope, pageScopeType, appName, supabase, immediateOrganisationId) {
1794
+ const effectiveScopeType = pageScopeType;
1795
+ if (effectiveScopeType === "both") {
1796
+ if (!scope.organisationId && !scope.eventId) {
1797
+ if (allowsOptionalContexts(appName)) {
1798
+ return {
1799
+ isValid: true,
1800
+ resolvedScope: {
1801
+ organisationId: void 0,
1802
+ eventId: void 0,
1803
+ appId: scope.appId
1804
+ },
1805
+ error: null
1806
+ };
1807
+ }
1808
+ return {
1809
+ isValid: false,
1810
+ resolvedScope: null,
1811
+ error: new Error("Page requires either organisation or event context")
1812
+ };
1813
+ }
1814
+ let organisationId = scope.organisationId || immediateOrganisationId || void 0;
1815
+ if (!organisationId && scope.eventId && supabase) {
1816
+ try {
1817
+ const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
1818
+ organisationId = derivedOrgId || void 0;
1819
+ } catch (error) {
1820
+ log3.warn("Failed to derive org from event for both-scope page:", error);
1821
+ }
1822
+ }
1823
+ return {
1824
+ isValid: true,
1825
+ resolvedScope: {
1826
+ organisationId,
1827
+ eventId: scope.eventId,
1828
+ appId: scope.appId
1829
+ },
1830
+ error: null
1831
+ };
1832
+ }
1833
+ if (effectiveScopeType === "event") {
1834
+ if (!scope.eventId) {
1835
+ if (allowsOptionalContexts(appName)) {
1836
+ return {
1837
+ isValid: true,
1838
+ resolvedScope: {
1839
+ organisationId: scope.organisationId,
1840
+ eventId: void 0,
1841
+ appId: scope.appId
1842
+ },
1843
+ error: null
1844
+ };
1845
+ }
1846
+ return {
1847
+ isValid: false,
1848
+ resolvedScope: null,
1849
+ error: new EventContextRequiredError()
1850
+ };
1851
+ }
1852
+ let organisationId = scope.organisationId || immediateOrganisationId || void 0;
1853
+ if (!organisationId && supabase && scope.eventId) {
1854
+ try {
1855
+ const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
1856
+ organisationId = derivedOrgId || void 0;
1857
+ if (!organisationId) {
1858
+ return {
1859
+ isValid: false,
1860
+ resolvedScope: null,
1861
+ error: new Error("Could not resolve organisation from event context")
1862
+ };
1863
+ }
1864
+ } catch (error) {
1865
+ log3.error("Failed to derive org from event:", error);
1866
+ return {
1867
+ isValid: false,
1868
+ resolvedScope: null,
1869
+ error: error instanceof Error ? error : new Error("Failed to derive organisation from event")
1870
+ };
1871
+ }
1872
+ }
1873
+ return {
1874
+ isValid: true,
1875
+ resolvedScope: {
1876
+ organisationId,
1877
+ eventId: scope.eventId,
1878
+ appId: scope.appId
1879
+ },
1880
+ error: null
1881
+ };
1882
+ }
1883
+ if (effectiveScopeType === "organisation") {
1884
+ if (!scope.organisationId) {
1885
+ if (allowsOptionalContexts(appName)) {
1886
+ return {
1887
+ isValid: true,
1888
+ resolvedScope: {
1889
+ organisationId: void 0,
1890
+ eventId: scope.eventId,
1891
+ appId: scope.appId
1892
+ },
1893
+ error: null
1894
+ };
1895
+ }
1896
+ return {
1897
+ isValid: false,
1898
+ resolvedScope: null,
1899
+ error: new OrganisationContextRequiredError()
1900
+ };
1901
+ }
1902
+ return {
1903
+ isValid: true,
1904
+ resolvedScope: {
1905
+ organisationId: scope.organisationId,
1906
+ eventId: scope.eventId,
1907
+ // Event is optional for org-scoped pages
1908
+ appId: scope.appId
1909
+ },
1910
+ error: null
1911
+ };
1912
+ }
1913
+ return {
1914
+ isValid: false,
1915
+ resolvedScope: null,
1916
+ error: new Error("Invalid scope type")
1917
+ };
1918
+ }
1919
+ };
1920
+
1921
+ // src/rbac/api.ts
1922
+ var log4 = createLogger("RBACAPI");
1923
+ function toApiError(error) {
1924
+ if (error instanceof RBACNotInitializedError) {
1925
+ return { code: "RBAC_NOT_INITIALIZED", message: error.message };
1926
+ }
1927
+ if (error instanceof OrganisationContextRequiredError) {
1928
+ return { code: "ORGANISATION_CONTEXT_REQUIRED", message: error.message };
1929
+ }
1930
+ const message = error instanceof Error ? error.message : String(error);
1931
+ return { code: "RBAC_ERROR", message };
1932
+ }
1933
+ var globalEngine = null;
1934
+ function setupRBAC(supabase, config) {
1935
+ const isDevelopment = import.meta.env.MODE === "development";
1936
+ const fullConfig = {
1937
+ supabase,
1938
+ debug: isDevelopment,
1939
+ logLevel: "warn",
1940
+ developmentMode: isDevelopment,
1941
+ ...config
1942
+ };
1943
+ createRBACConfig(fullConfig);
1944
+ const securityConfig = config === void 0 && !isDevelopment ? void 0 : {
1945
+ // Default: disable rate limiting in development
1946
+ ...isDevelopment && config?.security?.enableRateLimiting === void 0 ? { enableRateLimiting: false } : {},
1947
+ // Explicit config overrides defaults
1948
+ ...config?.security
1949
+ };
1950
+ globalEngine = createRBACEngine(supabase, securityConfig);
1951
+ const useBatchedAudit = config?.audit?.batched !== false && config?.performance?.enableBatchedAuditLogging !== false;
1952
+ const batchConfig = useBatchedAudit ? {
1953
+ batchWindow: config?.audit?.batchWindow,
1954
+ batchSize: config?.audit?.batchSize
1955
+ } : void 0;
1956
+ const auditManager = createAuditManager(supabase, useBatchedAudit, batchConfig);
1957
+ setGlobalAuditManager(auditManager);
1958
+ if (config?.performance?.enablePerformanceTracking) {
1959
+ enablePerformanceMonitoring();
1960
+ }
1961
+ }
1962
+ function isRBACInitialized() {
1963
+ return globalEngine !== null;
1964
+ }
1965
+ function getEngine() {
1966
+ if (!globalEngine) {
1967
+ throw new RBACNotInitializedError();
1968
+ }
1969
+ return globalEngine;
1970
+ }
1971
+ async function getAccessLevel(input, appName) {
1972
+ try {
1973
+ const engine = getEngine();
1974
+ const isSuperAdminUser = await engine["checkSuperAdmin"](input.userId);
1975
+ if (isSuperAdminUser) {
1976
+ return ok("super");
1977
+ }
1978
+ const validation = await ContextValidator.resolveScopeForPage(
1979
+ input.scope,
1980
+ "organisation",
1981
+ // Default to organisation scope when no page context
1982
+ appName,
1983
+ engine["supabase"]
1984
+ );
1985
+ if (!validation.isValid || !validation.resolvedScope) {
1986
+ throw validation.error || new OrganisationContextRequiredError();
1987
+ }
1988
+ const accessLevel = await engine.getAccessLevel({
1989
+ ...input,
1990
+ scope: validation.resolvedScope
1991
+ });
1992
+ return ok(accessLevel);
1993
+ } catch (error) {
1994
+ return err(toApiError(error));
1995
+ }
1996
+ }
1997
+ async function getPermissionMap(input, appName) {
1998
+ try {
1999
+ const engine = getEngine();
2000
+ const validation = await ContextValidator.resolveScopeForPage(
2001
+ input.scope,
2002
+ "organisation",
2003
+ // Default to organisation scope when no page context
2004
+ appName,
2005
+ engine["supabase"]
2006
+ );
2007
+ if (!validation.isValid || !validation.resolvedScope) {
2008
+ throw validation.error || new OrganisationContextRequiredError();
2009
+ }
2010
+ const permissionMap = await engine.getPermissionMap({
2011
+ ...input,
2012
+ scope: validation.resolvedScope
2013
+ });
2014
+ return ok(permissionMap);
2015
+ } catch (error) {
2016
+ return err(toApiError(error));
2017
+ }
2018
+ }
2019
+ async function resolveAppContext(input) {
2020
+ try {
2021
+ const engine = getEngine();
2022
+ const context = await engine.resolveAppContext(input);
2023
+ return ok(context);
2024
+ } catch (error) {
2025
+ return err(toApiError(error));
2026
+ }
2027
+ }
2028
+ async function getRoleContext(input, appName) {
2029
+ try {
2030
+ const engine = getEngine();
2031
+ const validation = await ContextValidator.resolveScopeForPage(
2032
+ input.scope,
2033
+ "organisation",
2034
+ // Default to organisation scope when no page context
2035
+ appName,
2036
+ engine["supabase"]
2037
+ );
2038
+ if (!validation.isValid || !validation.resolvedScope) {
2039
+ throw validation.error || new OrganisationContextRequiredError();
2040
+ }
2041
+ const roleContext = await engine.getRoleContext({
2042
+ ...input,
2043
+ scope: validation.resolvedScope
2044
+ });
2045
+ return ok(roleContext);
2046
+ } catch (error) {
2047
+ return err(toApiError(error));
2048
+ }
2049
+ }
2050
+ async function isPermitted(input, appName, precomputedSuperAdmin = null) {
2051
+ try {
2052
+ const engine = getEngine();
2053
+ if (precomputedSuperAdmin === true) {
2054
+ return ok(true);
2055
+ }
2056
+ if (precomputedSuperAdmin === null) {
2057
+ const isSuperAdminUser = await engine["checkSuperAdmin"](input.userId);
2058
+ if (isSuperAdminUser) {
2059
+ return ok(true);
2060
+ }
2061
+ }
2062
+ let resolvedAppName = appName;
2063
+ if (!resolvedAppName && input.scope.appId) {
2064
+ try {
2065
+ const { data } = await engine["supabase"].from("rbac_apps").select("name").eq("id", input.scope.appId).eq("is_active", true).single();
2066
+ if (data) {
2067
+ resolvedAppName = data.name;
2068
+ }
2069
+ } catch (_err) {
2070
+ }
2071
+ }
2072
+ let pageScopeType;
2073
+ if (input.pageId) {
2074
+ const scopeResult = await getPageScopeType(
2075
+ input.pageId,
2076
+ input.scope.appId,
2077
+ resolvedAppName
2078
+ );
2079
+ if (!scopeResult.ok) {
2080
+ log4.error("Failed to get page scope type:", scopeResult.error);
2081
+ return err(scopeResult.error);
2082
+ }
2083
+ if (!scopeResult.data) {
2084
+ return err({ code: "PAGE_SCOPE_TYPE_MISSING", message: `Page ${input.pageId} does not have scope_type set` });
2085
+ }
2086
+ pageScopeType = scopeResult.data;
2087
+ } else {
2088
+ pageScopeType = "organisation";
2089
+ }
2090
+ const validation = await ContextValidator.resolveScopeForPage(
2091
+ input.scope,
2092
+ pageScopeType,
2093
+ resolvedAppName,
2094
+ engine["supabase"]
2095
+ );
2096
+ if (!validation.isValid || !validation.resolvedScope) {
2097
+ throw validation.error || new OrganisationContextRequiredError();
2098
+ }
2099
+ const validatedScope = validation.resolvedScope;
2100
+ if (pageScopeType === "both" && input.pageId) {
2101
+ const eventScope = {
2102
+ organisationId: validatedScope.organisationId,
2103
+ // Org derived from event
2104
+ eventId: validatedScope.eventId,
2105
+ appId: validatedScope.appId
2106
+ };
2107
+ const eventSecurityContext = {
2108
+ userId: input.userId,
2109
+ organisationId: eventScope.organisationId || null,
2110
+ timestamp: /* @__PURE__ */ new Date()
2111
+ };
2112
+ const eventInput = {
2113
+ ...input,
2114
+ scope: eventScope
2115
+ };
2116
+ const hasEventPermission = await engine.isPermitted(eventInput, eventSecurityContext);
2117
+ if (validatedScope.organisationId && validatedScope.eventId) {
2118
+ const orgScope = {
2119
+ organisationId: validatedScope.organisationId,
2120
+ eventId: void 0,
2121
+ // Clear event for org-only check
2122
+ appId: validatedScope.appId
2123
+ };
2124
+ const orgSecurityContext = {
2125
+ userId: input.userId,
2126
+ organisationId: orgScope.organisationId || null,
2127
+ timestamp: /* @__PURE__ */ new Date()
2128
+ };
2129
+ const orgInput = {
2130
+ ...input,
2131
+ scope: orgScope
2132
+ };
2133
+ const hasOrgPermission = await engine.isPermitted(orgInput, orgSecurityContext);
2134
+ return ok(hasEventPermission || hasOrgPermission);
2135
+ }
2136
+ return ok(hasEventPermission);
2137
+ }
2138
+ const securityContext = {
2139
+ userId: input.userId,
2140
+ organisationId: validatedScope.organisationId || null,
2141
+ timestamp: /* @__PURE__ */ new Date()
2142
+ };
2143
+ const validatedInput = {
2144
+ ...input,
2145
+ scope: validatedScope
2146
+ };
2147
+ const permitted = await engine.isPermitted(validatedInput, securityContext);
2148
+ return ok(permitted);
2149
+ } catch (error) {
2150
+ return err(toApiError(error));
2151
+ }
2152
+ }
2153
+ async function isPermittedCached(input, appName) {
2154
+ const { userId, scope, permission, pageId } = input;
2155
+ const cacheKey = RBACCache.generatePermissionKey({
2156
+ userId,
2157
+ organisationId: scope.organisationId,
2158
+ eventId: scope.eventId,
2159
+ appId: scope.appId,
2160
+ permission,
2161
+ pageId
2162
+ });
2163
+ const cached = rbacCache.get(cacheKey, true);
2164
+ if (cached !== null) {
2165
+ return ok(cached);
2166
+ }
2167
+ return getOrCreateRequest(input, async (checkInput) => {
2168
+ const result = await isPermitted(checkInput, appName, null);
2169
+ if (!result.ok) {
2170
+ return result;
2171
+ }
2172
+ const isPageLevelCheck = !!pageId || permission.includes("page.");
2173
+ rbacCache.set(cacheKey, result.data, void 0, isPageLevelCheck);
2174
+ return ok(result.data);
2175
+ });
2176
+ }
2177
+ async function hasAnyPermission(input) {
2178
+ const { permissions, ...baseInput } = input;
2179
+ for (const permission of permissions) {
2180
+ const result = await isPermitted({
2181
+ ...baseInput,
2182
+ permission
2183
+ });
2184
+ if (!result.ok) {
2185
+ return result;
2186
+ }
2187
+ if (result.data) {
2188
+ return ok(true);
2189
+ }
2190
+ }
2191
+ return ok(false);
2192
+ }
2193
+ async function hasAllPermissions(input) {
2194
+ const { permissions, ...baseInput } = input;
2195
+ for (const permission of permissions) {
2196
+ const result = await isPermitted({
2197
+ ...baseInput,
2198
+ permission
2199
+ });
2200
+ if (!result.ok) {
2201
+ return result;
2202
+ }
2203
+ if (!result.data) {
2204
+ return ok(false);
2205
+ }
2206
+ }
2207
+ return ok(true);
2208
+ }
2209
+ async function isSuperAdmin(userId) {
2210
+ try {
2211
+ const engine = getEngine();
2212
+ const value = await engine["checkSuperAdmin"](userId);
2213
+ return ok(value);
2214
+ } catch (error) {
2215
+ return err(toApiError(error));
2216
+ }
2217
+ }
2218
+ async function getPageScopeType(pageId, appId, appName) {
2219
+ try {
2220
+ const engine = getEngine();
2221
+ let resolvedAppId = appId;
2222
+ if (!resolvedAppId && appName) {
2223
+ const { data: app, error: appError } = await engine["supabase"].from("rbac_apps").select("id, name, is_active").eq("name", appName).eq("is_active", true).maybeSingle();
2224
+ if (appError) {
2225
+ log4.error("Error resolving appId from appName", {
2226
+ appName,
2227
+ pageId,
2228
+ error: appError,
2229
+ errorMessage: appError instanceof Error ? appError.message : String(appError)
2230
+ });
2231
+ return err({ code: "APP_RESOLVE_FAILED", message: `Failed to resolve appId from appName "${appName}": ${appError instanceof Error ? appError.message : String(appError)}` });
2232
+ }
2233
+ if (!app) {
2234
+ log4.error("App not found or inactive", { appName, pageId });
2235
+ return err({ code: "APP_NOT_FOUND", message: `Could not resolve appId for appName "${appName}" - app not found or not active` });
2236
+ }
2237
+ resolvedAppId = app.id;
2238
+ }
2239
+ if (!resolvedAppId) {
2240
+ log4.error("No appId resolved", { pageId, appId, appName });
2241
+ return err({ code: "APP_ID_REQUIRED", message: `Could not resolve appId for page ${pageId} - appId and appName both missing or invalid` });
2242
+ }
2243
+ let resolvedPageId = pageId;
2244
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
2245
+ if (!uuidRegex.test(pageId)) {
2246
+ const { data: page, error: pageError } = await engine["supabase"].from("rbac_app_pages").select("id, page_name, app_id").eq("app_id", resolvedAppId).eq("page_name", pageId).maybeSingle();
2247
+ if (pageError) {
2248
+ log4.error("Error resolving pageId from page_name", { pageId, appId: resolvedAppId, appName, error: pageError });
2249
+ return err({ code: "PAGE_RESOLVE_FAILED", message: `Failed to resolve pageId "${pageId}" for appId ${resolvedAppId}: ${pageError instanceof Error ? pageError.message : String(pageError)}` });
2250
+ }
2251
+ if (!page) {
2252
+ log4.error("Page not found in database", { pageId, appId: resolvedAppId, appName });
2253
+ return err({ code: "PAGE_NOT_FOUND", message: `Could not resolve pageId "${pageId}" to a valid UUID - page not found for appId ${resolvedAppId}` });
2254
+ }
2255
+ resolvedPageId = page.id;
2256
+ }
2257
+ if (!uuidRegex.test(resolvedPageId)) {
2258
+ log4.error("PageId resolution failed - not a valid UUID", { originalPageId: pageId, resolvedPageId, appId: resolvedAppId, appName });
2259
+ return err({ code: "PAGE_ID_INVALID", message: `Could not resolve pageId ${pageId} to a valid UUID` });
2260
+ }
2261
+ const { data: pageData, error } = await engine["supabase"].from("rbac_app_pages").select("scope_type, page_name, app_id").eq("id", resolvedPageId).single();
2262
+ if (error) {
2263
+ log4.error("Error fetching page scope type from database", { pageId: resolvedPageId, originalPageId: pageId, appId: resolvedAppId, appName, error });
2264
+ return err({ code: "PAGE_SCOPE_FETCH_FAILED", message: `Failed to get page scope type: ${error instanceof Error ? error.message : String(error)}` });
2265
+ }
2266
+ if (!pageData || !pageData.scope_type) {
2267
+ log4.error("Page found but scope_type is missing", { pageId: resolvedPageId, originalPageId: pageId, appId: resolvedAppId, appName, pageData });
2268
+ return err({ code: "PAGE_SCOPE_TYPE_MISSING", message: `Page ${resolvedPageId} does not have scope_type set` });
2269
+ }
2270
+ return ok(pageData.scope_type);
2271
+ } catch (error) {
2272
+ log4.error("Error fetching page scope type (catch block)", { pageId, appId, appName, error });
2273
+ return err(toApiError(error));
2274
+ }
2275
+ }
2276
+ async function isOrganisationAdmin(userId, organisationId) {
2277
+ const result = await getAccessLevel({
2278
+ userId,
2279
+ scope: { organisationId }
2280
+ });
2281
+ if (!result.ok) {
2282
+ return result;
2283
+ }
2284
+ return ok(result.data === "admin" || result.data === "super");
2285
+ }
2286
+ async function isEventAdmin(userId, scope) {
2287
+ if (!scope.eventId || !scope.appId) {
2288
+ return ok(false);
2289
+ }
2290
+ const result = await getAccessLevel({ userId, scope });
2291
+ if (!result.ok) {
2292
+ return result;
2293
+ }
2294
+ return ok(result.data === "admin" || result.data === "super");
2295
+ }
2296
+ function invalidateUserCache(userId, organisationId) {
2297
+ const patterns = organisationId ? [
2298
+ CACHE_PATTERNS.PERMISSION(userId, organisationId),
2299
+ `access:${userId}:${organisationId}:`,
2300
+ `map:${userId}:${organisationId}:`
2301
+ ] : [
2302
+ `perm:${userId}:`,
2303
+ `access:${userId}:`,
2304
+ `map:${userId}:`
2305
+ ];
2306
+ patterns.forEach((pattern) => rbacCache.invalidate(pattern));
2307
+ }
2308
+ function invalidateOrganisationCache(organisationId) {
2309
+ rbacCache.invalidate(CACHE_PATTERNS.ORGANISATION(organisationId));
2310
+ }
2311
+ function invalidateEventCache(eventId) {
2312
+ rbacCache.invalidate(CACHE_PATTERNS.EVENT(eventId));
2313
+ }
2314
+ function invalidateAppCache(appId) {
2315
+ rbacCache.invalidate(CACHE_PATTERNS.APP(appId));
2316
+ }
2317
+ function clearCache() {
2318
+ rbacCache.clear();
2319
+ }
2320
+
2321
+ export { CACHE_PATTERNS, ContextValidator, EventContextRequiredError, OrganisationContextRequiredError, RBACCache, RBACEngine, 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 };