@jmruthers/pace-core 0.2.4

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 (1009) hide show
  1. package/CHANGELOG.md +202 -0
  2. package/README.md +299 -0
  3. package/dist/DataTable-BHlzyKZP.d.ts +116 -0
  4. package/dist/DataTable-GEY5U7OI.js +100 -0
  5. package/dist/DataTable-GEY5U7OI.js.map +1 -0
  6. package/dist/PublicLoadingSpinner-DztrzuJr.d.ts +3430 -0
  7. package/dist/UnifiedAuthProvider-w66zSCUf.d.ts +160 -0
  8. package/dist/api-GZHIDA4X.js +41 -0
  9. package/dist/api-GZHIDA4X.js.map +1 -0
  10. package/dist/appConfig-BVGyuvI7.d.ts +71 -0
  11. package/dist/appNameResolver-7GHF5ED2.js +22 -0
  12. package/dist/appNameResolver-7GHF5ED2.js.map +1 -0
  13. package/dist/audit-BUW3LMJB.js +16 -0
  14. package/dist/audit-BUW3LMJB.js.map +1 -0
  15. package/dist/chunk-22KLBHPS.js +29 -0
  16. package/dist/chunk-22KLBHPS.js.map +1 -0
  17. package/dist/chunk-24MKLB7U.js +81 -0
  18. package/dist/chunk-24MKLB7U.js.map +1 -0
  19. package/dist/chunk-2MKP6IYD.js +388 -0
  20. package/dist/chunk-2MKP6IYD.js.map +1 -0
  21. package/dist/chunk-2V3Y6YBC.js +114 -0
  22. package/dist/chunk-2V3Y6YBC.js.map +1 -0
  23. package/dist/chunk-5CDJCTOO.js +190 -0
  24. package/dist/chunk-5CDJCTOO.js.map +1 -0
  25. package/dist/chunk-6ZQVSHKL.js +1345 -0
  26. package/dist/chunk-6ZQVSHKL.js.map +1 -0
  27. package/dist/chunk-74C6SNEC.js +77 -0
  28. package/dist/chunk-74C6SNEC.js.map +1 -0
  29. package/dist/chunk-7BNPOCLL.js +178 -0
  30. package/dist/chunk-7BNPOCLL.js.map +1 -0
  31. package/dist/chunk-7JL3T7BO.js +3344 -0
  32. package/dist/chunk-7JL3T7BO.js.map +1 -0
  33. package/dist/chunk-CDQ3PX7L.js +18 -0
  34. package/dist/chunk-CDQ3PX7L.js.map +1 -0
  35. package/dist/chunk-DY5E3AT7.js +1734 -0
  36. package/dist/chunk-DY5E3AT7.js.map +1 -0
  37. package/dist/chunk-ETEJVKYK.js +6032 -0
  38. package/dist/chunk-ETEJVKYK.js.map +1 -0
  39. package/dist/chunk-I5Z3QH5X.js +32 -0
  40. package/dist/chunk-I5Z3QH5X.js.map +1 -0
  41. package/dist/chunk-MZBUOP4P.js +119 -0
  42. package/dist/chunk-MZBUOP4P.js.map +1 -0
  43. package/dist/chunk-N2EUGZRW.js +98 -0
  44. package/dist/chunk-N2EUGZRW.js.map +1 -0
  45. package/dist/chunk-NQ4TOOO6.js +20 -0
  46. package/dist/chunk-NQ4TOOO6.js.map +1 -0
  47. package/dist/chunk-OHXGNT3K.js +21 -0
  48. package/dist/chunk-OHXGNT3K.js.map +1 -0
  49. package/dist/chunk-OKXMUYIB.js +522 -0
  50. package/dist/chunk-OKXMUYIB.js.map +1 -0
  51. package/dist/chunk-PFRRIDYA.js +382 -0
  52. package/dist/chunk-PFRRIDYA.js.map +1 -0
  53. package/dist/chunk-PLDDJCW6.js +49 -0
  54. package/dist/chunk-PLDDJCW6.js.map +1 -0
  55. package/dist/chunk-SS3E6QLB.js +695 -0
  56. package/dist/chunk-SS3E6QLB.js.map +1 -0
  57. package/dist/chunk-TMRLB2LA.js +326 -0
  58. package/dist/chunk-TMRLB2LA.js.map +1 -0
  59. package/dist/chunk-WYB6MBZA.js +5533 -0
  60. package/dist/chunk-WYB6MBZA.js.map +1 -0
  61. package/dist/chunk-YDJW5XTN.js +84 -0
  62. package/dist/chunk-YDJW5XTN.js.map +1 -0
  63. package/dist/components.d.ts +1308 -0
  64. package/dist/components.js +3759 -0
  65. package/dist/components.js.map +1 -0
  66. package/dist/database-C3Szpi5J.d.ts +470 -0
  67. package/dist/hooks.d.ts +449 -0
  68. package/dist/hooks.js +612 -0
  69. package/dist/hooks.js.map +1 -0
  70. package/dist/index.d.ts +385 -0
  71. package/dist/index.js +569 -0
  72. package/dist/index.js.map +1 -0
  73. package/dist/organisation-CO3Sh3_D.d.ts +99 -0
  74. package/dist/providers.d.ts +45 -0
  75. package/dist/providers.js +36 -0
  76. package/dist/providers.js.map +1 -0
  77. package/dist/rbac/eslint-rules.d.ts +52 -0
  78. package/dist/rbac/eslint-rules.js +252 -0
  79. package/dist/rbac/eslint-rules.js.map +1 -0
  80. package/dist/rbac/index.d.ts +1918 -0
  81. package/dist/rbac/index.js +2212 -0
  82. package/dist/rbac/index.js.map +1 -0
  83. package/dist/styles/core.css +401 -0
  84. package/dist/styles/fonts/georama-italic.woff2 +0 -0
  85. package/dist/styles/fonts/georama.woff2 +0 -0
  86. package/dist/styles/fonts/open-sans-italic.woff2 +0 -0
  87. package/dist/styles/fonts/open-sans.woff2 +0 -0
  88. package/dist/styles/fonts/reddit-mono.woff2 +0 -0
  89. package/dist/styles/index.d.ts +36 -0
  90. package/dist/styles/index.js +24 -0
  91. package/dist/styles/index.js.map +1 -0
  92. package/dist/theming/runtime.d.ts +73 -0
  93. package/dist/theming/runtime.js +16 -0
  94. package/dist/theming/runtime.js.map +1 -0
  95. package/dist/types-CInEi-ng.d.ts +316 -0
  96. package/dist/types.d.ts +196 -0
  97. package/dist/types.js +83 -0
  98. package/dist/types.js.map +1 -0
  99. package/dist/unified-CM7T0aTK.d.ts +198 -0
  100. package/dist/useComponentPerformance-DE9l5RkL.d.ts +11 -0
  101. package/dist/usePublicRouteParams-B6i0KtXW.d.ts +477 -0
  102. package/dist/utils.d.ts +639 -0
  103. package/dist/utils.js +1103 -0
  104. package/dist/utils.js.map +1 -0
  105. package/dist/validation-PM_iOaTI.d.ts +159 -0
  106. package/dist/validation.d.ts +138 -0
  107. package/dist/validation.js +477 -0
  108. package/dist/validation.js.map +1 -0
  109. package/docs/INDEX.md +192 -0
  110. package/docs/README.md +165 -0
  111. package/docs/api/.nojekyll +1 -0
  112. package/docs/api/README.md +301 -0
  113. package/docs/api/classes/ErrorBoundary.md +144 -0
  114. package/docs/api/classes/PublicErrorBoundary.md +132 -0
  115. package/docs/api/interfaces/AggregateConfig.md +43 -0
  116. package/docs/api/interfaces/ButtonProps.md +53 -0
  117. package/docs/api/interfaces/CardProps.md +40 -0
  118. package/docs/api/interfaces/ColorPalette.md +7 -0
  119. package/docs/api/interfaces/ColorShade.md +41 -0
  120. package/docs/api/interfaces/DataTableAction.md +200 -0
  121. package/docs/api/interfaces/DataTableColumn.md +300 -0
  122. package/docs/api/interfaces/DataTableProps.md +517 -0
  123. package/docs/api/interfaces/DataTableToolbarButton.md +96 -0
  124. package/docs/api/interfaces/EmptyStateConfig.md +61 -0
  125. package/docs/api/interfaces/EventContextType.md +96 -0
  126. package/docs/api/interfaces/EventLogoProps.md +152 -0
  127. package/docs/api/interfaces/EventProviderProps.md +19 -0
  128. package/docs/api/interfaces/FileSizeLimits.md +7 -0
  129. package/docs/api/interfaces/FileUploadProps.md +154 -0
  130. package/docs/api/interfaces/FooterProps.md +105 -0
  131. package/docs/api/interfaces/InactivityWarningModalProps.md +115 -0
  132. package/docs/api/interfaces/InputProps.md +53 -0
  133. package/docs/api/interfaces/LabelProps.md +107 -0
  134. package/docs/api/interfaces/LoginFormProps.md +184 -0
  135. package/docs/api/interfaces/NavigationItem.md +176 -0
  136. package/docs/api/interfaces/NavigationMenuProps.md +236 -0
  137. package/docs/api/interfaces/Organisation.md +140 -0
  138. package/docs/api/interfaces/OrganisationContextType.md +377 -0
  139. package/docs/api/interfaces/OrganisationMembership.md +140 -0
  140. package/docs/api/interfaces/OrganisationProviderProps.md +19 -0
  141. package/docs/api/interfaces/OrganisationSecurityError.md +62 -0
  142. package/docs/api/interfaces/PaceAppLayoutProps.md +393 -0
  143. package/docs/api/interfaces/PaceLoginPageProps.md +34 -0
  144. package/docs/api/interfaces/PaletteData.md +41 -0
  145. package/docs/api/interfaces/PublicErrorBoundaryProps.md +94 -0
  146. package/docs/api/interfaces/PublicErrorBoundaryState.md +68 -0
  147. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +86 -0
  148. package/docs/api/interfaces/PublicPageFooterProps.md +112 -0
  149. package/docs/api/interfaces/PublicPageHeaderProps.md +138 -0
  150. package/docs/api/interfaces/PublicPageLayoutProps.md +138 -0
  151. package/docs/api/interfaces/StorageConfig.md +41 -0
  152. package/docs/api/interfaces/StorageFileInfo.md +74 -0
  153. package/docs/api/interfaces/StorageFileMetadata.md +140 -0
  154. package/docs/api/interfaces/StorageListOptions.md +86 -0
  155. package/docs/api/interfaces/StorageListResult.md +41 -0
  156. package/docs/api/interfaces/StorageUploadOptions.md +88 -0
  157. package/docs/api/interfaces/StorageUploadResult.md +63 -0
  158. package/docs/api/interfaces/StorageUrlOptions.md +47 -0
  159. package/docs/api/interfaces/StyleImport.md +19 -0
  160. package/docs/api/interfaces/ToastActionElement.md +9 -0
  161. package/docs/api/interfaces/ToastProps.md +9 -0
  162. package/docs/api/interfaces/UnifiedAuthContextType.md +1108 -0
  163. package/docs/api/interfaces/UnifiedAuthProviderProps.md +171 -0
  164. package/docs/api/interfaces/UseInactivityTrackerOptions.md +136 -0
  165. package/docs/api/interfaces/UseInactivityTrackerReturn.md +123 -0
  166. package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
  167. package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
  168. package/docs/api/interfaces/UsePublicEventOptions.md +34 -0
  169. package/docs/api/interfaces/UsePublicEventReturn.md +68 -0
  170. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +94 -0
  171. package/docs/api/interfaces/UserEventAccess.md +118 -0
  172. package/docs/api/interfaces/UserMenuProps.md +86 -0
  173. package/docs/api/interfaces/UserProfile.md +63 -0
  174. package/docs/api/modules.md +4153 -0
  175. package/docs/api-reference/components.md +1623 -0
  176. package/docs/api-reference/hooks.md +627 -0
  177. package/docs/api-reference/providers.md +487 -0
  178. package/docs/api-reference/types.md +1005 -0
  179. package/docs/api-reference/utilities.md +1104 -0
  180. package/docs/app.css.example +53 -0
  181. package/docs/architecture/README.md +577 -0
  182. package/docs/best-practices/README.md +400 -0
  183. package/docs/best-practices/deployment.md +1042 -0
  184. package/docs/best-practices/performance.md +789 -0
  185. package/docs/best-practices/security.md +881 -0
  186. package/docs/best-practices/testing.md +981 -0
  187. package/docs/consuming-app-example.md +290 -0
  188. package/docs/consuming-app-vite-config.md +233 -0
  189. package/docs/core-concepts/authentication.md +98 -0
  190. package/docs/core-concepts/events.md +756 -0
  191. package/docs/core-concepts/organisations.md +790 -0
  192. package/docs/core-concepts/permissions.md +729 -0
  193. package/docs/core-concepts/rbac-system.md +233 -0
  194. package/docs/database-schema-requirements.md +172 -0
  195. package/docs/documentation-style-checklist.md +294 -0
  196. package/docs/examples/navigation-menu-auth-fix.md +344 -0
  197. package/docs/getting-started/examples/README.md +106 -0
  198. package/docs/getting-started/examples/basic-auth-app.md +521 -0
  199. package/docs/getting-started/examples/full-featured-app.md +616 -0
  200. package/docs/getting-started/installation.md +269 -0
  201. package/docs/getting-started/quick-start.md +401 -0
  202. package/docs/implementation-guides/app-layout.md +983 -0
  203. package/docs/implementation-guides/data-tables.md +1898 -0
  204. package/docs/implementation-guides/dynamic-colors.md +195 -0
  205. package/docs/implementation-guides/forms.md +578 -0
  206. package/docs/implementation-guides/hierarchical-datatable.md +850 -0
  207. package/docs/implementation-guides/large-datasets.md +281 -0
  208. package/docs/implementation-guides/navigation.md +844 -0
  209. package/docs/implementation-guides/performance.md +403 -0
  210. package/docs/implementation-guides/permission-enforcement.md +764 -0
  211. package/docs/implementation-guides/public-pages.md +752 -0
  212. package/docs/migration/README.md +493 -0
  213. package/docs/migration/organisation-context-timing-fix.md +217 -0
  214. package/docs/migration/quick-migration-guide.md +320 -0
  215. package/docs/migration/rbac-migration.md +571 -0
  216. package/docs/migration/v0.4.15-tailwind-scanning.md +272 -0
  217. package/docs/migration/v0.4.16-css-first-approach.md +306 -0
  218. package/docs/migration/v0.4.17-source-path-fix.md +229 -0
  219. package/docs/migration-guide.md +168 -0
  220. package/docs/performance/README.md +551 -0
  221. package/docs/print-components/README.md +258 -0
  222. package/docs/print-components/api-reference.md +636 -0
  223. package/docs/print-components/examples/README.md +204 -0
  224. package/docs/print-components/examples/basic-report.tsx +92 -0
  225. package/docs/print-components/examples/card-catalog.tsx +149 -0
  226. package/docs/print-components/examples/cover-page-report.tsx +163 -0
  227. package/docs/print-components/quick-start.md +363 -0
  228. package/docs/quick-reference.md +576 -0
  229. package/docs/rbac/README.md +265 -0
  230. package/docs/rbac/advanced-patterns.md +776 -0
  231. package/docs/rbac/api-reference.md +1033 -0
  232. package/docs/rbac/examples.md +883 -0
  233. package/docs/rbac/getting-started.md +679 -0
  234. package/docs/rbac/quick-start.md +619 -0
  235. package/docs/rbac/super-admin-guide.md +592 -0
  236. package/docs/rbac/troubleshooting.md +316 -0
  237. package/docs/security/README.md +680 -0
  238. package/docs/security/checklist.md +343 -0
  239. package/docs/style-guide.md +522 -0
  240. package/docs/styles/README.md +319 -0
  241. package/docs/testing/README.md +874 -0
  242. package/docs/troubleshooting/README.md +497 -0
  243. package/docs/troubleshooting/common-issues.md +1563 -0
  244. package/docs/troubleshooting/database-view-compatibility.md +119 -0
  245. package/docs/troubleshooting/debugging.md +1117 -0
  246. package/docs/troubleshooting/migration.md +918 -0
  247. package/docs/troubleshooting/organisation-context-setup.md +277 -0
  248. package/docs/troubleshooting/react-hooks-issue-analysis.md +166 -0
  249. package/docs/troubleshooting/styling-issues.md +219 -0
  250. package/docs/troubleshooting/tailwind-content-scanning.md +213 -0
  251. package/docs/usage.md +175 -0
  252. package/docs/visual-testing.md +114 -0
  253. package/package.json +211 -0
  254. package/src/__mocks__/lucide-react.ts +181 -0
  255. package/src/__tests__/README.md +404 -0
  256. package/src/__tests__/debug-provider.unit.test.tsx +67 -0
  257. package/src/__tests__/e2e/workflows.test.tsx +373 -0
  258. package/src/__tests__/hybridPermissions.unit.test.tsx +474 -0
  259. package/src/__tests__/index.integration.test.ts +491 -0
  260. package/src/__tests__/mocks/MockAuthProvider-standalone.tsx +47 -0
  261. package/src/__tests__/mocks/MockAuthProvider.tsx +63 -0
  262. package/src/__tests__/mocks/enhancedSupabaseMock.ts +252 -0
  263. package/src/__tests__/mocks/index.test.ts +23 -0
  264. package/src/__tests__/mocks/index.ts +16 -0
  265. package/src/__tests__/mocks/mockAuth.ts +155 -0
  266. package/src/__tests__/mocks/mockSupabase.ts +83 -0
  267. package/src/__tests__/mocks/mockSupabaseClient.ts +63 -0
  268. package/src/__tests__/mocks/providers.tsx +22 -0
  269. package/src/__tests__/patterns/__tests__/testPatterns.test.ts +394 -0
  270. package/src/__tests__/patterns/testPatterns.ts +124 -0
  271. package/src/__tests__/performance/componentPerformance.performance.test.ts +27 -0
  272. package/src/__tests__/performance/index.ts +24 -0
  273. package/src/__tests__/performance/performanceValidation.performance.test.ts +15 -0
  274. package/src/__tests__/security/security.unit.test.tsx +7 -0
  275. package/src/__tests__/security/securityValidation.security.test.tsx +153 -0
  276. package/src/__tests__/setup.ts +259 -0
  277. package/src/__tests__/setupTests.d.ts +1 -0
  278. package/src/__tests__/shared/componentTestUtils.tsx +475 -0
  279. package/src/__tests__/shared/errorHandlingTestUtils.ts +107 -0
  280. package/src/__tests__/shared/index.ts +81 -0
  281. package/src/__tests__/shared/integrationTestUtils.tsx +375 -0
  282. package/src/__tests__/shared/performanceTestUtils.tsx +476 -0
  283. package/src/__tests__/shared/testUtils.optimized.tsx +627 -0
  284. package/src/__tests__/simple.test.tsx +20 -0
  285. package/src/__tests__/templates/accessibility.test.template.tsx +279 -0
  286. package/src/__tests__/templates/component.test.template.tsx +122 -0
  287. package/src/__tests__/templates/integration.test.template.tsx +199 -0
  288. package/src/__tests__/test-utils/dataFactories.ts +60 -0
  289. package/src/__tests__/test-utils/index.ts +6 -0
  290. package/src/__tests__/typeSafety.unit.test.ts +65 -0
  291. package/src/__tests__/unifiedAuth.unit.test.tsx +151 -0
  292. package/src/__tests__/utils/accessibilityHelpers.ts +254 -0
  293. package/src/__tests__/utils/assertions.ts +50 -0
  294. package/src/__tests__/utils/deterministicHelpers.ts +31 -0
  295. package/src/__tests__/utils/edgeCaseConfig.test.ts +75 -0
  296. package/src/__tests__/utils/edgeCaseConfig.ts +98 -0
  297. package/src/__tests__/utils/mockHelpers.ts +149 -0
  298. package/src/__tests__/utils/mockLoader.ts +101 -0
  299. package/src/__tests__/utils/performanceHelpers.ts +55 -0
  300. package/src/__tests__/utils/performanceTestHelpers.ts +68 -0
  301. package/src/__tests__/utils/testDataFactories.ts +28 -0
  302. package/src/__tests__/utils/testIsolation.ts +67 -0
  303. package/src/__tests__/utils/visualTestHelpers.ts +20 -0
  304. package/src/__tests__/visual/__snapshots__/componentSnapshots.visual.test.tsx.snap +68 -0
  305. package/src/__tests__/visual/__snapshots__/componentVisuals.visual.test.tsx.snap +14 -0
  306. package/src/__tests__/visual/__snapshots__/visualRegression.test.tsx.snap +217 -0
  307. package/src/__tests__/visual/__snapshots__/visualRegression.visual.test.tsx.snap +24 -0
  308. package/src/__tests__/visual/componentSnapshots.visual.test.tsx +33 -0
  309. package/src/__tests__/visual/componentVisuals.visual.test.tsx +12 -0
  310. package/src/__tests__/visual/visualRegression.visual.test.tsx +20 -0
  311. package/src/components/Alert/Alert.tsx +134 -0
  312. package/src/components/Alert/__tests__/Alert.unit.test.tsx +381 -0
  313. package/src/components/Alert/index.ts +2 -0
  314. package/src/components/Avatar/Avatar.tsx +84 -0
  315. package/src/components/Avatar/__tests__/Avatar.unit.test.tsx +232 -0
  316. package/src/components/Avatar/index.ts +2 -0
  317. package/src/components/Button/Button.tsx +270 -0
  318. package/src/components/Button/__tests__/Button.accessibility.test.tsx +131 -0
  319. package/src/components/Button/__tests__/Button.comprehensive.test.tsx +721 -0
  320. package/src/components/Button/__tests__/Button.unit.test.tsx +189 -0
  321. package/src/components/Button/__tests__/EventSelector.integration.test.tsx +285 -0
  322. package/src/components/Button/index.ts +2 -0
  323. package/src/components/Card/Card.tsx +271 -0
  324. package/src/components/Card/__tests__/Card.accessibility.test.tsx +394 -0
  325. package/src/components/Card/__tests__/Card.comprehensive.test.tsx +599 -0
  326. package/src/components/Card/__tests__/Card.integration.test.tsx +673 -0
  327. package/src/components/Card/__tests__/Card.performance.test.tsx +546 -0
  328. package/src/components/Card/__tests__/Card.unit.test.tsx +330 -0
  329. package/src/components/Card/__tests__/Card.visual.test.tsx +599 -0
  330. package/src/components/Card/__tests__/README.md +211 -0
  331. package/src/components/Card/index.ts +1 -0
  332. package/src/components/Checkbox/Checkbox.tsx +75 -0
  333. package/src/components/Checkbox/__mocks__/Checkbox.tsx +2 -0
  334. package/src/components/Checkbox/__tests__/Checkbox.unit.test.tsx +520 -0
  335. package/src/components/Checkbox/index.ts +2 -0
  336. package/src/components/DataTable/DataTable.tsx +440 -0
  337. package/src/components/DataTable/__tests__/DataTable.autoSizing.test.tsx +526 -0
  338. package/src/components/DataTable/__tests__/DataTable.errorHandling.test.tsx +259 -0
  339. package/src/components/DataTable/__tests__/DataTable.hierarchical.test.tsx +675 -0
  340. package/src/components/DataTable/__tests__/DataTable.infinite-loop.test.tsx +324 -0
  341. package/src/components/DataTable/__tests__/DataTable.integration.test.tsx +724 -0
  342. package/src/components/DataTable/__tests__/DataTable.performance.test.tsx +597 -0
  343. package/src/components/DataTable/__tests__/DataTable.permissions.test.tsx +306 -0
  344. package/src/components/DataTable/__tests__/DataTable.regressionFixes.test.tsx +546 -0
  345. package/src/components/DataTable/__tests__/DataTable.selection.controlled.test.tsx +386 -0
  346. package/src/components/DataTable/__tests__/DataTable.selection.test.tsx +338 -0
  347. package/src/components/DataTable/__tests__/DataTable.userWorkflows.test.tsx +310 -0
  348. package/src/components/DataTable/__tests__/DataTable.workflowValidation.test.tsx +489 -0
  349. package/src/components/DataTable/__tests__/DataTable.workflows.test.tsx +701 -0
  350. package/src/components/DataTable/__tests__/README.md +136 -0
  351. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +66 -0
  352. package/src/components/DataTable/__tests__/performance-regression.test.tsx +788 -0
  353. package/src/components/DataTable/__tests__/performance.test.tsx +365 -0
  354. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +103 -0
  355. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +382 -0
  356. package/src/components/DataTable/__tests__/test-utils.ts +94 -0
  357. package/src/components/DataTable/components/ActionButtons.tsx +177 -0
  358. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +160 -0
  359. package/src/components/DataTable/components/ColumnFilter.tsx +114 -0
  360. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +100 -0
  361. package/src/components/DataTable/components/DataTableBody.tsx +462 -0
  362. package/src/components/DataTable/components/DataTableCore.tsx +869 -0
  363. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +214 -0
  364. package/src/components/DataTable/components/DataTableHeader.tsx +31 -0
  365. package/src/components/DataTable/components/DataTableModals.tsx +87 -0
  366. package/src/components/DataTable/components/DataTableToolbar.tsx +251 -0
  367. package/src/components/DataTable/components/DraggableColumnHeader.tsx +148 -0
  368. package/src/components/DataTable/components/EditableRow.tsx +160 -0
  369. package/src/components/DataTable/components/EmptyState.tsx +64 -0
  370. package/src/components/DataTable/components/ExpandButton.tsx +113 -0
  371. package/src/components/DataTable/components/FilterRow.tsx +101 -0
  372. package/src/components/DataTable/components/GroupHeader.tsx +42 -0
  373. package/src/components/DataTable/components/GroupingDropdown.tsx +96 -0
  374. package/src/components/DataTable/components/ImportModal.tsx +345 -0
  375. package/src/components/DataTable/components/LoadingState.tsx +12 -0
  376. package/src/components/DataTable/components/PaginationControls.tsx +332 -0
  377. package/src/components/DataTable/components/UnifiedTableBody.tsx +911 -0
  378. package/src/components/DataTable/components/ViewRowModal.tsx +68 -0
  379. package/src/components/DataTable/components/VirtualizedDataTable.tsx +593 -0
  380. package/src/components/DataTable/components/__tests__/ActionButtons.unit.test.tsx +150 -0
  381. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +224 -0
  382. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.unit.test.tsx +244 -0
  383. package/src/components/DataTable/components/__tests__/DataTable.accessibility.test.tsx +523 -0
  384. package/src/components/DataTable/components/__tests__/DataTable.integration.test.tsx +401 -0
  385. package/src/components/DataTable/components/__tests__/DataTable.performance.test.tsx +161 -0
  386. package/src/components/DataTable/components/__tests__/DataTable.real.test.tsx +251 -0
  387. package/src/components/DataTable/components/__tests__/DataTable.security.test.tsx +172 -0
  388. package/src/components/DataTable/components/__tests__/DataTable.unit.test.tsx +290 -0
  389. package/src/components/DataTable/components/__tests__/DataTableBody.unit.test.tsx +147 -0
  390. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.unit.test.tsx +182 -0
  391. package/src/components/DataTable/components/__tests__/DataTableHeader.unit.test.tsx +143 -0
  392. package/src/components/DataTable/components/__tests__/DataTableModals.unit.test.tsx +123 -0
  393. package/src/components/DataTable/components/__tests__/EditableRow.unit.test.tsx +660 -0
  394. package/src/components/DataTable/components/__tests__/EmptyState.unit.test.tsx +256 -0
  395. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +498 -0
  396. package/src/components/DataTable/components/__tests__/FilterRow.unit.test.tsx +112 -0
  397. package/src/components/DataTable/components/__tests__/FilteringToggle.unit.test.tsx +130 -0
  398. package/src/components/DataTable/components/__tests__/GroupHeader.unit.test.tsx +172 -0
  399. package/src/components/DataTable/components/__tests__/GroupingDropdown.unit.test.tsx +222 -0
  400. package/src/components/DataTable/components/__tests__/ImportModal.unit.test.tsx +780 -0
  401. package/src/components/DataTable/components/__tests__/LoadingState.unit.test.tsx +65 -0
  402. package/src/components/DataTable/components/__tests__/PaginationControls.unit.test.tsx +634 -0
  403. package/src/components/DataTable/components/__tests__/StateComponents.unit.test.tsx +48 -0
  404. package/src/components/DataTable/components/__tests__/UnifiedTableBody.hierarchical.test.tsx +541 -0
  405. package/src/components/DataTable/components/__tests__/ViewRowModal.unit.test.tsx +228 -0
  406. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.unit.test.tsx +568 -0
  407. package/src/components/DataTable/components/index.ts +17 -0
  408. package/src/components/DataTable/context/DataTableContext.tsx +97 -0
  409. package/src/components/DataTable/core/ActionManager.ts +235 -0
  410. package/src/components/DataTable/core/ColumnFactory.ts +268 -0
  411. package/src/components/DataTable/core/ColumnManager.ts +205 -0
  412. package/src/components/DataTable/core/DataManager.ts +188 -0
  413. package/src/components/DataTable/core/DataTableContext.tsx +182 -0
  414. package/src/components/DataTable/core/LocalDataAdapter.ts +264 -0
  415. package/src/components/DataTable/core/PluginRegistry.ts +229 -0
  416. package/src/components/DataTable/core/StateManager.ts +311 -0
  417. package/src/components/DataTable/core/__tests__/ActionManager.unit.test.ts +405 -0
  418. package/src/components/DataTable/core/__tests__/ArchitectureIntegration.unit.test.tsx +445 -0
  419. package/src/components/DataTable/core/__tests__/ColumnFactory.unit.test.ts +288 -0
  420. package/src/components/DataTable/core/__tests__/ColumnManager.unit.test.ts +623 -0
  421. package/src/components/DataTable/core/__tests__/DataManager.unit.test.ts +431 -0
  422. package/src/components/DataTable/core/__tests__/DataTableContext.unit.test.tsx +433 -0
  423. package/src/components/DataTable/core/__tests__/LocalDataAdapter.unit.test.ts +422 -0
  424. package/src/components/DataTable/core/__tests__/PluginRegistry.unit.test.tsx +207 -0
  425. package/src/components/DataTable/core/__tests__/StateManager.unit.test.ts +278 -0
  426. package/src/components/DataTable/core/index.ts +8 -0
  427. package/src/components/DataTable/core/interfaces.ts +338 -0
  428. package/src/components/DataTable/examples/AutoSizingExample.tsx +180 -0
  429. package/src/components/DataTable/examples/ColumnSizingComparison.tsx +235 -0
  430. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +418 -0
  431. package/src/components/DataTable/examples/HierarchicalExample.tsx +472 -0
  432. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +173 -0
  433. package/src/components/DataTable/examples/PerformanceExample.tsx +502 -0
  434. package/src/components/DataTable/examples/__tests__/PerformanceExample.unit.test.tsx +281 -0
  435. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.unit.test.ts +407 -0
  436. package/src/components/DataTable/hooks/__tests__/useColumnReordering.unit.test.ts +679 -0
  437. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +95 -0
  438. package/src/components/DataTable/hooks/useColumnReordering.ts +110 -0
  439. package/src/components/DataTable/hooks/useDataTableState.ts +325 -0
  440. package/src/components/DataTable/hooks/useHierarchicalState.ts +174 -0
  441. package/src/components/DataTable/index.ts +70 -0
  442. package/src/components/DataTable/styles.ts +171 -0
  443. package/src/components/DataTable/types.ts +475 -0
  444. package/src/components/DataTable/utils/__tests__/columnSizing.test.ts +237 -0
  445. package/src/components/DataTable/utils/__tests__/debugTools.unit.test.ts +267 -0
  446. package/src/components/DataTable/utils/__tests__/errorHandling.unit.test.ts +467 -0
  447. package/src/components/DataTable/utils/__tests__/exportUtils.unit.test.ts +380 -0
  448. package/src/components/DataTable/utils/__tests__/flexibleImport.unit.test.ts +233 -0
  449. package/src/components/DataTable/utils/__tests__/performanceUtils.unit.test.ts +414 -0
  450. package/src/components/DataTable/utils/columnSizing.ts +125 -0
  451. package/src/components/DataTable/utils/debugTools.ts +583 -0
  452. package/src/components/DataTable/utils/errorHandling.ts +494 -0
  453. package/src/components/DataTable/utils/exportUtils.ts +126 -0
  454. package/src/components/DataTable/utils/flexibleImport.ts +510 -0
  455. package/src/components/DataTable/utils/hierarchicalSorting.ts +151 -0
  456. package/src/components/DataTable/utils/hierarchicalUtils.ts +218 -0
  457. package/src/components/DataTable/utils/index.ts +1 -0
  458. package/src/components/DataTable/utils/performanceUtils.ts +351 -0
  459. package/src/components/Dialog/Dialog.tsx +782 -0
  460. package/src/components/Dialog/README.md +804 -0
  461. package/src/components/Dialog/__tests__/Dialog.accessibility.test.tsx +521 -0
  462. package/src/components/Dialog/__tests__/Dialog.auto-size.example.tsx +157 -0
  463. package/src/components/Dialog/__tests__/Dialog.enhanced.test.tsx +538 -0
  464. package/src/components/Dialog/__tests__/Dialog.unit.test.tsx +1373 -0
  465. package/src/components/Dialog/examples/BasicHtmlTest.tsx +55 -0
  466. package/src/components/Dialog/examples/DebugHtmlExample.tsx +68 -0
  467. package/src/components/Dialog/examples/HtmlDialogExample.tsx +202 -0
  468. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +61 -0
  469. package/src/components/Dialog/examples/SmartDialogExample.tsx +322 -0
  470. package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +151 -0
  471. package/src/components/Dialog/index.ts +12 -0
  472. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +611 -0
  473. package/src/components/Dialog/utils/safeHtml.ts +185 -0
  474. package/src/components/ErrorBoundary/ErrorBoundary.tsx +312 -0
  475. package/src/components/ErrorBoundary/__tests__/ErrorBoundary.accessibility.test.tsx +517 -0
  476. package/src/components/ErrorBoundary/__tests__/ErrorBoundary.integration.test.tsx +572 -0
  477. package/src/components/ErrorBoundary/__tests__/ErrorBoundary.unit.test.tsx +579 -0
  478. package/src/components/ErrorBoundary/index.ts +8 -0
  479. package/src/components/EventSelector/EventSelector.tsx +360 -0
  480. package/src/components/EventSelector/__tests__/EventSelector.test.tsx +528 -0
  481. package/src/components/EventSelector/index.ts +3 -0
  482. package/src/components/EventSelector/types.ts +79 -0
  483. package/src/components/FileUpload/FileUpload.example.tsx +218 -0
  484. package/src/components/FileUpload/FileUpload.tsx +237 -0
  485. package/src/components/FileUpload/__tests__/FileUpload.integration.test.tsx +992 -0
  486. package/src/components/FileUpload/__tests__/FileUpload.real.test.tsx +927 -0
  487. package/src/components/FileUpload/__tests__/FileUpload.test.tsx +855 -0
  488. package/src/components/FileUpload/__tests__/FileUpload.unit.test.tsx +1311 -0
  489. package/src/components/FileUpload/__tests__/FileUpload.unmocked.test.tsx +937 -0
  490. package/src/components/FileUpload/index.ts +6 -0
  491. package/src/components/Footer/Footer.tsx +197 -0
  492. package/src/components/Footer/__tests__/Footer.accessibility.test.tsx +359 -0
  493. package/src/components/Footer/__tests__/Footer.integration.test.tsx +353 -0
  494. package/src/components/Footer/__tests__/Footer.performance.test.tsx +309 -0
  495. package/src/components/Footer/__tests__/Footer.unit.test.tsx +309 -0
  496. package/src/components/Footer/__tests__/Footer.visual.test.tsx +335 -0
  497. package/src/components/Footer/index.ts +17 -0
  498. package/src/components/Form/Form.tsx +166 -0
  499. package/src/components/Form/FormErrorSummary.tsx +113 -0
  500. package/src/components/Form/FormField.tsx +249 -0
  501. package/src/components/Form/FormFieldset.tsx +127 -0
  502. package/src/components/Form/FormLiveRegion.tsx +198 -0
  503. package/src/components/Form/__tests__/Form.accessibility.test.tsx +820 -0
  504. package/src/components/Form/__tests__/Form.unit.test.tsx +305 -0
  505. package/src/components/Form/__tests__/FormErrorSummary.unit.test.tsx +285 -0
  506. package/src/components/Form/__tests__/FormFieldset.unit.test.tsx +241 -0
  507. package/src/components/Form/index.ts +26 -0
  508. package/src/components/Header/Header.tsx +301 -0
  509. package/src/components/Header/__tests__/Header.accessibility.test.tsx +382 -0
  510. package/src/components/Header/__tests__/Header.comprehensive.test.tsx +509 -0
  511. package/src/components/Header/__tests__/Header.unit.test.tsx +335 -0
  512. package/src/components/Header/index.ts +4 -0
  513. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +196 -0
  514. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +164 -0
  515. package/src/components/InactivityWarningModal/__tests__/InactivityWarningModal.unit.test.tsx +224 -0
  516. package/src/components/InactivityWarningModal/index.ts +9 -0
  517. package/src/components/Input/Input.tsx +201 -0
  518. package/src/components/Input/__mocks__/Input.tsx +2 -0
  519. package/src/components/Input/__tests__/Input.accessibility.test.tsx +632 -0
  520. package/src/components/Input/__tests__/Input.unit.test.tsx +1121 -0
  521. package/src/components/Input/index.ts +9 -0
  522. package/src/components/Label/Label.tsx +186 -0
  523. package/src/components/Label/__tests__/Label.accessibility.test.tsx +239 -0
  524. package/src/components/Label/__tests__/Label.unit.test.tsx +331 -0
  525. package/src/components/Label/index.ts +2 -0
  526. package/src/components/LoadingSpinner/LoadingSpinner.tsx +98 -0
  527. package/src/components/LoadingSpinner/__tests__/LoadingSpinner.accessibility.test.tsx +116 -0
  528. package/src/components/LoadingSpinner/__tests__/LoadingSpinner.unit.test.tsx +144 -0
  529. package/src/components/LoadingSpinner/index.ts +3 -0
  530. package/src/components/LoginForm/LoginForm.tsx +273 -0
  531. package/src/components/LoginForm/__tests__/LoginForm.accessibility.test.tsx +201 -0
  532. package/src/components/LoginForm/__tests__/LoginForm.unit.test.tsx +119 -0
  533. package/src/components/LoginForm/index.ts +3 -0
  534. package/src/components/NavigationMenu/NavigationMenu.tsx +698 -0
  535. package/src/components/NavigationMenu/__tests__/NavigationMenu.accessibility.test.tsx +378 -0
  536. package/src/components/NavigationMenu/__tests__/NavigationMenu.enhanced.test.tsx +768 -0
  537. package/src/components/NavigationMenu/__tests__/NavigationMenu.integration.test.tsx +576 -0
  538. package/src/components/NavigationMenu/__tests__/NavigationMenu.performance.test.tsx +585 -0
  539. package/src/components/NavigationMenu/__tests__/NavigationMenu.real.component.test.tsx +783 -0
  540. package/src/components/NavigationMenu/__tests__/NavigationMenu.security.enhanced.test.tsx +810 -0
  541. package/src/components/NavigationMenu/__tests__/NavigationMenu.security.test.tsx +494 -0
  542. package/src/components/NavigationMenu/__tests__/NavigationMenu.unit.test.tsx +331 -0
  543. package/src/components/NavigationMenu/__tests__/NavigationMenu.userWorkflows.test.tsx +347 -0
  544. package/src/components/NavigationMenu/__tests__/NavigationMenu.workflows.test.tsx +584 -0
  545. package/src/components/NavigationMenu/index.ts +10 -0
  546. package/src/components/NavigationMenu/types.ts +85 -0
  547. package/src/components/OrganisationSelector/OrganisationSelector.tsx +304 -0
  548. package/src/components/OrganisationSelector/__tests__/OrganisationSelector.unit.test.tsx +664 -0
  549. package/src/components/OrganisationSelector/index.ts +9 -0
  550. package/src/components/PaceAppLayout/PaceAppLayout.tsx +699 -0
  551. package/src/components/PaceAppLayout/README.md +278 -0
  552. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +288 -0
  553. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +889 -0
  554. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +629 -0
  555. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +782 -0
  556. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +904 -0
  557. package/src/components/PaceAppLayout/index.ts +1 -0
  558. package/src/components/PaceLoginPage/PaceLoginPage.tsx +221 -0
  559. package/src/components/PaceLoginPage/__tests__/PaceLoginPage.accessibility.test.tsx +463 -0
  560. package/src/components/PaceLoginPage/__tests__/PaceLoginPage.integration.test.tsx +586 -0
  561. package/src/components/PaceLoginPage/__tests__/PaceLoginPage.unit.test.tsx +533 -0
  562. package/src/components/PaceLoginPage/index.ts +1 -0
  563. package/src/components/PasswordReset/PasswordChangeForm.tsx +186 -0
  564. package/src/components/PasswordReset/PasswordResetForm.tsx +201 -0
  565. package/src/components/PasswordReset/__tests__/PasswordChangeForm.accessibility.test.tsx +408 -0
  566. package/src/components/PasswordReset/__tests__/PasswordChangeForm.unit.test.tsx +561 -0
  567. package/src/components/PasswordReset/__tests__/PasswordReset.integration.test.tsx +304 -0
  568. package/src/components/PasswordReset/__tests__/PasswordResetForm.accessibility.test.tsx +20 -0
  569. package/src/components/PasswordReset/__tests__/PasswordResetForm.unit.test.tsx +523 -0
  570. package/src/components/PasswordReset/__tests__/__mocks__/UnifiedAuthProvider.ts +29 -0
  571. package/src/components/PasswordReset/index.ts +4 -0
  572. package/src/components/Print/__tests__/Print.comprehensive.test.tsx +331 -0
  573. package/src/components/PrintButton/PrintButton.tsx +321 -0
  574. package/src/components/PrintButton/PrintButtonGroup.tsx +84 -0
  575. package/src/components/PrintButton/PrintToolbar.tsx +94 -0
  576. package/src/components/PrintButton/__tests__/PrintButton.unit.test.tsx +429 -0
  577. package/src/components/PrintButton/__tests__/PrintButtonGroup.unit.test.tsx +277 -0
  578. package/src/components/PrintButton/__tests__/PrintToolbar.unit.test.tsx +264 -0
  579. package/src/components/PrintButton/examples/PrintButtonShowcase.tsx +438 -0
  580. package/src/components/PrintButton/index.ts +33 -0
  581. package/src/components/PrintButton/types.ts +173 -0
  582. package/src/components/PrintCard/PrintCard.tsx +154 -0
  583. package/src/components/PrintCard/PrintCardContent.tsx +57 -0
  584. package/src/components/PrintCard/PrintCardFooter.tsx +60 -0
  585. package/src/components/PrintCard/PrintCardGrid.tsx +91 -0
  586. package/src/components/PrintCard/PrintCardHeader.tsx +78 -0
  587. package/src/components/PrintCard/PrintCardImage.tsx +81 -0
  588. package/src/components/PrintCard/__tests__/PrintCard.unit.test.tsx +233 -0
  589. package/src/components/PrintCard/__tests__/PrintCardContent.test.tsx +284 -0
  590. package/src/components/PrintCard/__tests__/PrintCardGrid.unit.test.tsx +214 -0
  591. package/src/components/PrintCard/__tests__/PrintCardImage.unit.test.tsx +264 -0
  592. package/src/components/PrintCard/examples/PrintCardShowcase.tsx +239 -0
  593. package/src/components/PrintCard/index.ts +34 -0
  594. package/src/components/PrintCard/types.ts +171 -0
  595. package/src/components/PrintDataTable/PrintDataTable.tsx +215 -0
  596. package/src/components/PrintDataTable/PrintTableGroup.tsx +90 -0
  597. package/src/components/PrintDataTable/PrintTableRow.tsx +76 -0
  598. package/src/components/PrintDataTable/__tests__/PrintDataTable.unit.test.tsx +361 -0
  599. package/src/components/PrintDataTable/__tests__/PrintTableGroup.unit.test.tsx +314 -0
  600. package/src/components/PrintDataTable/__tests__/PrintTableRow.unit.test.tsx +362 -0
  601. package/src/components/PrintDataTable/index.ts +25 -0
  602. package/src/components/PrintDataTable/types.ts +67 -0
  603. package/src/components/PrintFooter/PrintFooter.tsx +183 -0
  604. package/src/components/PrintFooter/PrintFooterContent.tsx +71 -0
  605. package/src/components/PrintFooter/PrintFooterInfo.tsx +86 -0
  606. package/src/components/PrintFooter/PrintPageNumber.tsx +90 -0
  607. package/src/components/PrintFooter/__tests__/PrintFooter.unit.test.tsx +500 -0
  608. package/src/components/PrintFooter/__tests__/PrintFooterContent.unit.test.tsx +321 -0
  609. package/src/components/PrintFooter/__tests__/PrintFooterInfo.unit.test.tsx +335 -0
  610. package/src/components/PrintFooter/__tests__/PrintPageNumber.unit.test.tsx +340 -0
  611. package/src/components/PrintFooter/examples/PrintFooterShowcase.tsx +390 -0
  612. package/src/components/PrintFooter/index.ts +30 -0
  613. package/src/components/PrintFooter/types.ts +149 -0
  614. package/src/components/PrintGrid/PrintGrid.tsx +180 -0
  615. package/src/components/PrintGrid/PrintGridBreakpoint.tsx +109 -0
  616. package/src/components/PrintGrid/PrintGridContainer.tsx +128 -0
  617. package/src/components/PrintGrid/PrintGridItem.tsx +220 -0
  618. package/src/components/PrintGrid/__tests__/PrintGrid.unit.test.tsx +340 -0
  619. package/src/components/PrintGrid/__tests__/PrintGridBreakpoint.unit.test.tsx +261 -0
  620. package/src/components/PrintGrid/__tests__/PrintGridContainer.unit.test.tsx +338 -0
  621. package/src/components/PrintGrid/__tests__/PrintGridItem.unit.test.tsx +338 -0
  622. package/src/components/PrintGrid/examples/PrintGridShowcase.tsx +359 -0
  623. package/src/components/PrintGrid/index.ts +31 -0
  624. package/src/components/PrintGrid/types.ts +159 -0
  625. package/src/components/PrintHeader/PrintCoverHeader.tsx +230 -0
  626. package/src/components/PrintHeader/PrintHeader.tsx +150 -0
  627. package/src/components/PrintHeader/__tests__/PrintCoverHeader.unit.test.tsx +309 -0
  628. package/src/components/PrintHeader/__tests__/PrintHeader.unit.test.tsx +202 -0
  629. package/src/components/PrintHeader/index.ts +17 -0
  630. package/src/components/PrintHeader/types.ts +42 -0
  631. package/src/components/PrintLayout/PrintLayout.tsx +122 -0
  632. package/src/components/PrintLayout/PrintLayoutContext.tsx +66 -0
  633. package/src/components/PrintLayout/PrintPageBreak.tsx +52 -0
  634. package/src/components/PrintLayout/__tests__/PrintLayout.unit.test.tsx +238 -0
  635. package/src/components/PrintLayout/examples/PrintShowcase.tsx +230 -0
  636. package/src/components/PrintLayout/index.ts +19 -0
  637. package/src/components/PrintLayout/types.ts +37 -0
  638. package/src/components/PrintPageBreak/PrintPageBreak.tsx +120 -0
  639. package/src/components/PrintPageBreak/PrintPageBreakGroup.tsx +90 -0
  640. package/src/components/PrintPageBreak/PrintPageBreakIndicator.tsx +112 -0
  641. package/src/components/PrintPageBreak/__tests__/PrintPageBreak.unit.test.tsx +263 -0
  642. package/src/components/PrintPageBreak/__tests__/PrintPageBreakGroup.unit.test.tsx +239 -0
  643. package/src/components/PrintPageBreak/__tests__/PrintPageBreakIndicator.unit.test.tsx +235 -0
  644. package/src/components/PrintPageBreak/examples/PrintPageBreakShowcase.tsx +279 -0
  645. package/src/components/PrintPageBreak/index.ts +23 -0
  646. package/src/components/PrintPageBreak/types.ts +94 -0
  647. package/src/components/PrintSection/PrintColumn.tsx +104 -0
  648. package/src/components/PrintSection/PrintDivider.tsx +101 -0
  649. package/src/components/PrintSection/PrintSection.tsx +129 -0
  650. package/src/components/PrintSection/PrintSectionContent.tsx +75 -0
  651. package/src/components/PrintSection/PrintSectionHeader.tsx +97 -0
  652. package/src/components/PrintSection/__tests__/PrintColumn.unit.test.tsx +385 -0
  653. package/src/components/PrintSection/__tests__/PrintDivider.unit.test.tsx +373 -0
  654. package/src/components/PrintSection/__tests__/PrintSection.unit.test.tsx +390 -0
  655. package/src/components/PrintSection/__tests__/PrintSectionContent.unit.test.tsx +321 -0
  656. package/src/components/PrintSection/__tests__/PrintSectionHeader.unit.test.tsx +334 -0
  657. package/src/components/PrintSection/examples/PrintSectionShowcase.tsx +258 -0
  658. package/src/components/PrintSection/index.ts +33 -0
  659. package/src/components/PrintSection/types.ts +155 -0
  660. package/src/components/PrintText/PrintText.tsx +116 -0
  661. package/src/components/PrintText/__tests__/PrintText.unit.test.tsx +351 -0
  662. package/src/components/PrintText/index.ts +16 -0
  663. package/src/components/PrintText/types.ts +24 -0
  664. package/src/components/Progress/Progress.tsx +116 -0
  665. package/src/components/Progress/__tests__/Progress.accessibility.test.tsx +240 -0
  666. package/src/components/Progress/__tests__/Progress.unit.test.tsx +242 -0
  667. package/src/components/Progress/index.ts +3 -0
  668. package/src/components/PublicLayout/EventLogo.tsx +287 -0
  669. package/src/components/PublicLayout/PublicErrorBoundary.tsx +279 -0
  670. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +208 -0
  671. package/src/components/PublicLayout/PublicPageContextChecker.tsx +130 -0
  672. package/src/components/PublicLayout/PublicPageDebugger.tsx +104 -0
  673. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +162 -0
  674. package/src/components/PublicLayout/PublicPageFooter.tsx +124 -0
  675. package/src/components/PublicLayout/PublicPageHeader.tsx +178 -0
  676. package/src/components/PublicLayout/PublicPageLayout.tsx +232 -0
  677. package/src/components/PublicLayout/PublicPageProvider.tsx +137 -0
  678. package/src/components/PublicLayout/__tests__/EventLogo.test.tsx +761 -0
  679. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.simplified.test.tsx +228 -0
  680. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +228 -0
  681. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +459 -0
  682. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +362 -0
  683. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +522 -0
  684. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +599 -0
  685. package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +513 -0
  686. package/src/components/PublicLayout/index.ts +51 -0
  687. package/src/components/RBAC/PagePermissionGuard.tsx +274 -0
  688. package/src/components/RBAC/RBACGuard.tsx +143 -0
  689. package/src/components/RBAC/RBACProvider.tsx +186 -0
  690. package/src/components/RBAC/RoleBasedContent.tsx +129 -0
  691. package/src/components/RBAC/__tests__/PagePermissionGuard.unit.test.tsx +674 -0
  692. package/src/components/RBAC/__tests__/RBAC.integration.test.tsx +573 -0
  693. package/src/components/RBAC/__tests__/RBACGuard.unit.test.tsx +467 -0
  694. package/src/components/RBAC/__tests__/RBACProvider.accessibility.test.tsx +475 -0
  695. package/src/components/RBAC/__tests__/RBACProvider.advanced.test.tsx +569 -0
  696. package/src/components/RBAC/__tests__/RBACProvider.integration.test.tsx +352 -0
  697. package/src/components/RBAC/__tests__/RBACProvider.unit.test.tsx +128 -0
  698. package/src/components/RBAC/__tests__/RoleBasedContent.unit.test.tsx +657 -0
  699. package/src/components/RBAC/index.ts +23 -0
  700. package/src/components/Select/Select.tsx +654 -0
  701. package/src/components/Select/__tests__/SearchableSelect.unit.test.tsx +437 -0
  702. package/src/components/Select/__tests__/Select.accessibility.test.tsx +1202 -0
  703. package/src/components/Select/__tests__/Select.actual.test.tsx +774 -0
  704. package/src/components/Select/__tests__/Select.comprehensive.test.tsx +837 -0
  705. package/src/components/Select/__tests__/Select.enhanced.test.tsx +1101 -0
  706. package/src/components/Select/__tests__/Select.integration.test.tsx +772 -0
  707. package/src/components/Select/__tests__/Select.performance.test.tsx +695 -0
  708. package/src/components/Select/__tests__/Select.real-world.test.tsx +1046 -0
  709. package/src/components/Select/__tests__/Select.search-algorithms.test.tsx +968 -0
  710. package/src/components/Select/__tests__/Select.unit.test.tsx +647 -0
  711. package/src/components/Select/__tests__/Select.utils.test.tsx +890 -0
  712. package/src/components/Select/index.ts +1 -0
  713. package/src/components/SuperAdminGuard.tsx +116 -0
  714. package/src/components/Table/Table.tsx +222 -0
  715. package/src/components/Table/__tests__/Table.accessibility.test.tsx +233 -0
  716. package/src/components/Table/__tests__/Table.unit.test.tsx +235 -0
  717. package/src/components/Table/index.ts +11 -0
  718. package/src/components/Toast/Toast.tsx +339 -0
  719. package/src/components/Toast/__tests__/Toast.accessibility.test.tsx +238 -0
  720. package/src/components/Toast/__tests__/Toast.integration.test.tsx +699 -0
  721. package/src/components/Toast/__tests__/Toast.unit.test.tsx +750 -0
  722. package/src/components/Toast/index.ts +14 -0
  723. package/src/components/Tooltip/Tooltip.tsx +167 -0
  724. package/src/components/Tooltip/__tests__/Tooltip.accessibility.test.tsx +121 -0
  725. package/src/components/Tooltip/__tests__/Tooltip.unit.test.tsx +185 -0
  726. package/src/components/Tooltip/index.ts +7 -0
  727. package/src/components/UserMenu/UserMenu.tsx +243 -0
  728. package/src/components/UserMenu/__tests__/UserMenu.accessibility.test.tsx +139 -0
  729. package/src/components/UserMenu/__tests__/UserMenu.integration.test.tsx +188 -0
  730. package/src/components/UserMenu/__tests__/UserMenu.unit.test.tsx +458 -0
  731. package/src/components/UserMenu/index.ts +3 -0
  732. package/src/components/__tests__/EdgeCaseTesting.enhanced.test.tsx +523 -0
  733. package/src/components/__tests__/ErrorTesting.enhanced.test.tsx +455 -0
  734. package/src/components/__tests__/SuperAdminGuard.test.tsx +456 -0
  735. package/src/components/__tests__/SuperAdminGuard.unit.test.tsx +456 -0
  736. package/src/components/examples/PermissionExample.tsx +150 -0
  737. package/src/components/examples/__tests__/PermissionExample.unit.test.tsx +360 -0
  738. package/src/components/index.ts +434 -0
  739. package/src/components.ts +19 -0
  740. package/src/constants/performance.ts +14 -0
  741. package/src/examples/CorrectPublicPageImplementation.tsx +301 -0
  742. package/src/examples/PublicEventPage.tsx +274 -0
  743. package/src/examples/PublicPageApp.tsx +308 -0
  744. package/src/examples/PublicPageUsageExample.tsx +216 -0
  745. package/src/fonts/georama-italic.woff2 +0 -0
  746. package/src/fonts/georama.woff2 +0 -0
  747. package/src/fonts/open-sans-italic.woff2 +0 -0
  748. package/src/fonts/open-sans.woff2 +0 -0
  749. package/src/fonts/reddit-mono.woff2 +0 -0
  750. package/src/hooks/__tests__/hooks.integration.test.tsx +575 -0
  751. package/src/hooks/__tests__/useApiFetch.unit.test.ts +115 -0
  752. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +133 -0
  753. package/src/hooks/__tests__/useDebounce.unit.test.ts +82 -0
  754. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +293 -0
  755. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +385 -0
  756. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +286 -0
  757. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +838 -0
  758. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +627 -0
  759. package/src/hooks/__tests__/useRBAC.unit.test.ts +903 -0
  760. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +537 -0
  761. package/src/hooks/__tests__/useToast.unit.test.tsx +62 -0
  762. package/src/hooks/__tests__/useZodForm.unit.test.tsx +37 -0
  763. package/src/hooks/index.ts +56 -0
  764. package/src/hooks/public/__tests__/usePublicEvent.test.tsx +397 -0
  765. package/src/hooks/public/__tests__/usePublicEventLogo.test.tsx +690 -0
  766. package/src/hooks/public/__tests__/usePublicRouteParams.test.tsx +449 -0
  767. package/src/hooks/public/index.ts +34 -0
  768. package/src/hooks/public/usePublicEvent.ts +261 -0
  769. package/src/hooks/public/usePublicEventLogo.ts +285 -0
  770. package/src/hooks/public/usePublicRouteParams.ts +259 -0
  771. package/src/hooks/useAppConfig.ts +94 -0
  772. package/src/hooks/useComponentPerformance.ts +39 -0
  773. package/src/hooks/useDataTablePerformance.ts +387 -0
  774. package/src/hooks/useDataTableState.ts +110 -0
  775. package/src/hooks/useDebounce.ts +18 -0
  776. package/src/hooks/useFocusManagement.ts +161 -0
  777. package/src/hooks/useFocusTrap.ts +155 -0
  778. package/src/hooks/useInactivityTracker.ts +372 -0
  779. package/src/hooks/useIsMobile.ts +42 -0
  780. package/src/hooks/useKeyboardShortcuts.ts +237 -0
  781. package/src/hooks/useOrganisationPermissions.ts +208 -0
  782. package/src/hooks/useOrganisationSecurity.ts +262 -0
  783. package/src/hooks/usePerformanceMonitor.ts +128 -0
  784. package/src/hooks/usePermissionCache.ts +455 -0
  785. package/src/hooks/useRBAC.ts +262 -0
  786. package/src/hooks/useSecureDataAccess.ts +586 -0
  787. package/src/hooks/useStorage.ts +274 -0
  788. package/src/hooks/useToast.ts +242 -0
  789. package/src/hooks/useZodForm.ts +28 -0
  790. package/src/index.ts +200 -0
  791. package/src/providers/AuthProvider.tsx +369 -0
  792. package/src/providers/EventProvider.tsx +324 -0
  793. package/src/providers/InactivityProvider.tsx +238 -0
  794. package/src/providers/OrganisationProvider.tsx +588 -0
  795. package/src/providers/RBACProvider.tsx +622 -0
  796. package/src/providers/UnifiedAuthProvider.tsx +327 -0
  797. package/src/providers/__tests__/EventProvider.unit.test.tsx +768 -0
  798. package/src/providers/__tests__/OrganisationProvider.basic.test.tsx +116 -0
  799. package/src/providers/__tests__/OrganisationProvider.unit.test.tsx +1312 -0
  800. package/src/providers/__tests__/UnifiedAuthProvider.inactivity.test.tsx +601 -0
  801. package/src/providers/__tests__/UnifiedAuthProvider.unit.test.tsx +675 -0
  802. package/src/providers/__tests__/index.unit.test.ts +78 -0
  803. package/src/providers/index.ts +15 -0
  804. package/src/rbac/README.md +885 -0
  805. package/src/rbac/__tests__/PagePermissionGuard.test.tsx +673 -0
  806. package/src/rbac/__tests__/README.md +170 -0
  807. package/src/rbac/__tests__/RoleBasedRouter.test.tsx +709 -0
  808. package/src/rbac/__tests__/TestContext.tsx +72 -0
  809. package/src/rbac/__tests__/__mocks__/cache.ts +144 -0
  810. package/src/rbac/__tests__/__mocks__/supabase.ts +152 -0
  811. package/src/rbac/__tests__/adapters-hooks-comprehensive.test.tsx +782 -0
  812. package/src/rbac/__tests__/adapters-hooks.test.tsx +561 -0
  813. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +963 -0
  814. package/src/rbac/__tests__/adapters.test.tsx +444 -0
  815. package/src/rbac/__tests__/api.test.ts +620 -0
  816. package/src/rbac/__tests__/audit-observability-comprehensive.test.ts +792 -0
  817. package/src/rbac/__tests__/audit-observability.test.ts +549 -0
  818. package/src/rbac/__tests__/audit.test.ts +616 -0
  819. package/src/rbac/__tests__/build-contract-compliance-simple.test.ts +230 -0
  820. package/src/rbac/__tests__/cache-invalidation-comprehensive.test.ts +889 -0
  821. package/src/rbac/__tests__/cache-invalidation.test.ts +457 -0
  822. package/src/rbac/__tests__/cache.test.ts +458 -0
  823. package/src/rbac/__tests__/components-navigation-guard.enhanced.test.tsx +859 -0
  824. package/src/rbac/__tests__/components-navigation-guard.test.tsx +895 -0
  825. package/src/rbac/__tests__/components-navigation-provider.test.tsx +692 -0
  826. package/src/rbac/__tests__/components-page-permission-guard.test.tsx +673 -0
  827. package/src/rbac/__tests__/components-page-permission-provider.test.tsx +614 -0
  828. package/src/rbac/__tests__/components-permission-enforcer.enhanced.fixed.test.tsx +836 -0
  829. package/src/rbac/__tests__/components-permission-enforcer.enhanced.test.tsx +837 -0
  830. package/src/rbac/__tests__/components-permission-enforcer.test.tsx +825 -0
  831. package/src/rbac/__tests__/components-role-based-router.test.tsx +709 -0
  832. package/src/rbac/__tests__/components-secure-data-provider.test.tsx +607 -0
  833. package/src/rbac/__tests__/config.test.ts +583 -0
  834. package/src/rbac/__tests__/core-logic-unit.test.ts +190 -0
  835. package/src/rbac/__tests__/core-permission-logic-comprehensive.test.ts +1467 -0
  836. package/src/rbac/__tests__/core-permission-logic-fixed.test.ts +151 -0
  837. package/src/rbac/__tests__/core-permission-logic-simple.test.ts +968 -0
  838. package/src/rbac/__tests__/core-permission-logic.test.ts +966 -0
  839. package/src/rbac/__tests__/edge-cases-comprehensive.test.ts +988 -0
  840. package/src/rbac/__tests__/edge-cases.test.ts +654 -0
  841. package/src/rbac/__tests__/engine.test.ts +361 -0
  842. package/src/rbac/__tests__/engine.unit.test.ts +361 -0
  843. package/src/rbac/__tests__/hooks.enhanced.test.tsx +979 -0
  844. package/src/rbac/__tests__/hooks.fixed.test.tsx +475 -0
  845. package/src/rbac/__tests__/hooks.test.tsx +385 -0
  846. package/src/rbac/__tests__/index.test.ts +269 -0
  847. package/src/rbac/__tests__/integration.enhanced.test.tsx +824 -0
  848. package/src/rbac/__tests__/page-permission-guard-super-admin.test.tsx +261 -0
  849. package/src/rbac/__tests__/performance.enhanced.test.tsx +724 -0
  850. package/src/rbac/__tests__/permissions.test.ts +383 -0
  851. package/src/rbac/__tests__/requires-event.test.ts +330 -0
  852. package/src/rbac/__tests__/scope-isolation-comprehensive.test.ts +1349 -0
  853. package/src/rbac/__tests__/scope-isolation.test.ts +755 -0
  854. package/src/rbac/__tests__/secure-client-rls-comprehensive.test.ts +592 -0
  855. package/src/rbac/__tests__/secure-client-rls.test.ts +377 -0
  856. package/src/rbac/__tests__/security.test.ts +296 -0
  857. package/src/rbac/__tests__/setup.ts +228 -0
  858. package/src/rbac/__tests__/test-utils-enhanced.tsx +400 -0
  859. package/src/rbac/__tests__/types.test.ts +685 -0
  860. package/src/rbac/adapters.tsx +726 -0
  861. package/src/rbac/api.ts +337 -0
  862. package/src/rbac/audit-enhanced.ts +339 -0
  863. package/src/rbac/audit.ts +338 -0
  864. package/src/rbac/cache.ts +213 -0
  865. package/src/rbac/components/EnhancedNavigationMenu.tsx +294 -0
  866. package/src/rbac/components/NavigationGuard.tsx +294 -0
  867. package/src/rbac/components/NavigationProvider.tsx +314 -0
  868. package/src/rbac/components/PagePermissionGuard.tsx +430 -0
  869. package/src/rbac/components/PagePermissionProvider.tsx +274 -0
  870. package/src/rbac/components/PermissionEnforcer.tsx +307 -0
  871. package/src/rbac/components/RoleBasedRouter.tsx +425 -0
  872. package/src/rbac/components/SecureDataProvider.tsx +319 -0
  873. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +631 -0
  874. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +667 -0
  875. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +647 -0
  876. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +496 -0
  877. package/src/rbac/components/index.ts +64 -0
  878. package/src/rbac/config.ts +133 -0
  879. package/src/rbac/docs/event-based-apps.md +285 -0
  880. package/src/rbac/engine.ts +1026 -0
  881. package/src/rbac/eslint-rules.js +285 -0
  882. package/src/rbac/examples/CompleteRBACExample.tsx +323 -0
  883. package/src/rbac/examples/EventBasedApp.tsx +238 -0
  884. package/src/rbac/hooks.ts +555 -0
  885. package/src/rbac/index.ts +114 -0
  886. package/src/rbac/permissions.ts +293 -0
  887. package/src/rbac/secureClient.ts +244 -0
  888. package/src/rbac/security.ts +346 -0
  889. package/src/rbac/testing/__tests__/index.test.tsx +342 -0
  890. package/src/rbac/testing/index.tsx +340 -0
  891. package/src/rbac/types.ts +341 -0
  892. package/src/rbac/utils/__tests__/eventContext.test.ts +428 -0
  893. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +428 -0
  894. package/src/rbac/utils/eventContext.ts +83 -0
  895. package/src/styles/__tests__/styles.unit.test.ts +164 -0
  896. package/src/styles/core.css +401 -0
  897. package/src/styles/index.ts +51 -0
  898. package/src/test-dom-cleanup.test.tsx +38 -0
  899. package/src/theming/__tests__/README.md +335 -0
  900. package/src/theming/__tests__/runtime.accessibility.test.ts +474 -0
  901. package/src/theming/__tests__/runtime.error.test.ts +616 -0
  902. package/src/theming/__tests__/runtime.integration.test.ts +376 -0
  903. package/src/theming/__tests__/runtime.performance.test.ts +411 -0
  904. package/src/theming/__tests__/runtime.unit.test.ts +470 -0
  905. package/src/theming/runtime.ts +187 -0
  906. package/src/types/__tests__/database.unit.test.ts +489 -0
  907. package/src/types/__tests__/guards.unit.test.ts +146 -0
  908. package/src/types/__tests__/index.unit.test.ts +77 -0
  909. package/src/types/__tests__/organisation.unit.test.ts +713 -0
  910. package/src/types/__tests__/rbac.unit.test.ts +621 -0
  911. package/src/types/__tests__/security.unit.test.ts +347 -0
  912. package/src/types/__tests__/supabase.unit.test.ts +658 -0
  913. package/src/types/__tests__/theme.unit.test.ts +218 -0
  914. package/src/types/__tests__/unified.unit.test.ts +537 -0
  915. package/src/types/__tests__/validation.unit.test.ts +616 -0
  916. package/src/types/database.ts +472 -0
  917. package/src/types/guards.ts +30 -0
  918. package/src/types/index.ts +25 -0
  919. package/src/types/organisation.ts +184 -0
  920. package/src/types/security.ts +70 -0
  921. package/src/types/supabase.ts +166 -0
  922. package/src/types/theme.ts +6 -0
  923. package/src/types/unified.ts +262 -0
  924. package/src/types/validation.ts +164 -0
  925. package/src/types/vitest-globals.d.ts +43 -0
  926. package/src/utils/__mocks__/supabaseMock.ts +75 -0
  927. package/src/utils/__mocks__/supabaseMock.tsx +198 -0
  928. package/src/utils/__tests__/appConfig.unit.test.ts +55 -0
  929. package/src/utils/__tests__/appNameResolver.unit.test.ts +137 -0
  930. package/src/utils/__tests__/audit.unit.test.ts +69 -0
  931. package/src/utils/__tests__/auth-utils.unit.test.ts +70 -0
  932. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +317 -0
  933. package/src/utils/__tests__/cn.unit.test.ts +34 -0
  934. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +480 -0
  935. package/src/utils/__tests__/dynamicUtils.unit.test.ts +322 -0
  936. package/src/utils/__tests__/formatDate.unit.test.ts +109 -0
  937. package/src/utils/__tests__/formatting.unit.test.ts +66 -0
  938. package/src/utils/__tests__/index.unit.test.ts +251 -0
  939. package/src/utils/__tests__/lazyLoad.unit.test.tsx +309 -0
  940. package/src/utils/__tests__/organisationContext.unit.test.ts +192 -0
  941. package/src/utils/__tests__/performanceBudgets.unit.test.ts +259 -0
  942. package/src/utils/__tests__/permissionTypes.unit.test.ts +250 -0
  943. package/src/utils/__tests__/permissionUtils.unit.test.ts +362 -0
  944. package/src/utils/__tests__/sanitization.unit.test.ts +346 -0
  945. package/src/utils/__tests__/schemaUtils.unit.test.ts +441 -0
  946. package/src/utils/__tests__/secureDataAccess.unit.test.ts +334 -0
  947. package/src/utils/__tests__/secureErrors.unit.test.ts +377 -0
  948. package/src/utils/__tests__/secureStorage.unit.test.ts +293 -0
  949. package/src/utils/__tests__/security.unit.test.ts +127 -0
  950. package/src/utils/__tests__/securityMonitor.unit.test.ts +280 -0
  951. package/src/utils/__tests__/sessionTracking.unit.test.ts +370 -0
  952. package/src/utils/__tests__/validation.unit.test.ts +84 -0
  953. package/src/utils/__tests__/validationUtils.unit.test.ts +571 -0
  954. package/src/utils/appConfig.ts +47 -0
  955. package/src/utils/appIdResolver.ts +130 -0
  956. package/src/utils/appNameResolver.ts +190 -0
  957. package/src/utils/audit.ts +127 -0
  958. package/src/utils/auth-utils.ts +96 -0
  959. package/src/utils/bundleAnalysis.ts +129 -0
  960. package/src/utils/cn.ts +7 -0
  961. package/src/utils/debugLogger.ts +46 -0
  962. package/src/utils/deviceFingerprint.ts +215 -0
  963. package/src/utils/dynamicUtils.ts +105 -0
  964. package/src/utils/formatting.ts +77 -0
  965. package/src/utils/index.ts +145 -0
  966. package/src/utils/lazyLoad.tsx +44 -0
  967. package/src/utils/organisationContext.ts +135 -0
  968. package/src/utils/performanceBenchmark.ts +64 -0
  969. package/src/utils/performanceBudgets.ts +111 -0
  970. package/src/utils/permissionTypes.ts +37 -0
  971. package/src/utils/permissionUtils.ts +31 -0
  972. package/src/utils/print/PrintDataProcessor.ts +390 -0
  973. package/src/utils/print/__tests__/PrintDataProcessor.unit.test.ts +219 -0
  974. package/src/utils/print/__tests__/usePrintOptimization.unit.test.tsx +353 -0
  975. package/src/utils/print/examples/PrintUtilitiesShowcase.tsx +397 -0
  976. package/src/utils/print/index.ts +29 -0
  977. package/src/utils/print/types.ts +196 -0
  978. package/src/utils/print/usePrintOptimization.ts +272 -0
  979. package/src/utils/sanitization.ts +264 -0
  980. package/src/utils/schemaUtils.ts +37 -0
  981. package/src/utils/secureDataAccess.ts +361 -0
  982. package/src/utils/secureErrors.ts +79 -0
  983. package/src/utils/secureStorage.ts +244 -0
  984. package/src/utils/security.ts +156 -0
  985. package/src/utils/securityMonitor.ts +45 -0
  986. package/src/utils/sessionTracking.ts +170 -0
  987. package/src/utils/storage/README.md +348 -0
  988. package/src/utils/storage/__tests__/config.unit.test.ts +206 -0
  989. package/src/utils/storage/__tests__/helpers.unit.test.ts +646 -0
  990. package/src/utils/storage/__tests__/index.unit.test.ts +167 -0
  991. package/src/utils/storage/__tests__/types.unit.test.ts +441 -0
  992. package/src/utils/storage/config.ts +100 -0
  993. package/src/utils/storage/helpers.ts +359 -0
  994. package/src/utils/storage/index.ts +36 -0
  995. package/src/utils/storage/types.ts +90 -0
  996. package/src/utils/validation.ts +111 -0
  997. package/src/utils/validationUtils.ts +120 -0
  998. package/src/validation/__tests__/common.unit.test.ts +101 -0
  999. package/src/validation/__tests__/csrf.unit.test.ts +302 -0
  1000. package/src/validation/__tests__/passwordSchema.unit.test.ts +98 -0
  1001. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +466 -0
  1002. package/src/validation/common.ts +53 -0
  1003. package/src/validation/csrf.ts +214 -0
  1004. package/src/validation/index.ts +43 -0
  1005. package/src/validation/passwordSchema.ts +125 -0
  1006. package/src/validation/sanitization.ts +96 -0
  1007. package/src/validation/schemaUtils.ts +42 -0
  1008. package/src/validation/sqlInjectionProtection.ts +242 -0
  1009. package/src/validation/user.ts +34 -0
@@ -0,0 +1,1026 @@
1
+ /**
2
+ * RBAC Core Engine
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Engine
5
+ * @since 1.0.0
6
+ *
7
+ * This module implements the core RBAC permission algorithm with deny-overrides-allow precedence.
8
+ */
9
+
10
+ import { SupabaseClient } from '@supabase/supabase-js';
11
+ import { Database } from '../types/database';
12
+ import {
13
+ UUID,
14
+ Permission,
15
+ Scope,
16
+ PermissionCheck,
17
+ AccessLevel,
18
+ PermissionMap,
19
+ Operation,
20
+ OrganisationRole,
21
+ EventAppRole
22
+ } from './types';
23
+ import { rbacCache, RBACCache } from './cache';
24
+ import { emitAuditEvent } from './audit';
25
+ import { getCurrentAppName } from '../utils/appNameResolver';
26
+ import {
27
+ RBACSecurityValidator,
28
+ RBACSecurityMiddleware,
29
+ SecurityContext,
30
+ DEFAULT_SECURITY_CONFIG
31
+ } from './security';
32
+
33
+ /**
34
+ * Grant type for permission resolution
35
+ */
36
+ interface Grant {
37
+ type: 'allow' | 'deny';
38
+ permission: Permission;
39
+ scope: 'global' | 'organisation' | 'eventApp' | 'page';
40
+ source: string;
41
+ }
42
+
43
+ /**
44
+ * RBAC Engine
45
+ *
46
+ * Implements the core permission algorithm with deny-overrides-allow precedence.
47
+ */
48
+ export class RBACEngine {
49
+ private supabase: SupabaseClient<Database>;
50
+ private securityMiddleware: RBACSecurityMiddleware;
51
+
52
+ constructor(supabase: SupabaseClient<Database>) {
53
+ this.supabase = supabase;
54
+ this.securityMiddleware = new RBACSecurityMiddleware(DEFAULT_SECURITY_CONFIG);
55
+ }
56
+
57
+ /**
58
+ * Check if a user has a specific permission
59
+ *
60
+ * @param input - Permission check input
61
+ * @param securityContext - Optional security context for enhanced validation
62
+ * @returns Promise resolving to permission result
63
+ */
64
+ async isPermitted(input: PermissionCheck, securityContext?: SecurityContext): Promise<boolean> {
65
+ const startTime = Date.now();
66
+ const { userId, permission, scope, pageId } = input;
67
+
68
+ try {
69
+ // Security validation
70
+ if (securityContext) {
71
+ const validation = await this.securityMiddleware.validateInput(input, securityContext);
72
+ if (!validation.isValid) {
73
+ RBACSecurityValidator.logSecurityEvent({
74
+ type: 'invalid_input',
75
+ userId,
76
+ details: { errors: validation.errors, input: JSON.stringify(input) },
77
+ });
78
+ return false;
79
+ }
80
+
81
+ const rateLimit = await this.securityMiddleware.checkRateLimit(securityContext);
82
+ if (!rateLimit.isAllowed) {
83
+ RBACSecurityValidator.logSecurityEvent({
84
+ type: 'rate_limit_exceeded',
85
+ userId,
86
+ details: { remaining: rateLimit.remaining },
87
+ });
88
+ return false;
89
+ }
90
+ }
91
+
92
+ // Input validation (only when security context is provided)
93
+ if (securityContext) {
94
+ if (!RBACSecurityValidator.validateUserId(userId)) {
95
+ RBACSecurityValidator.logSecurityEvent({
96
+ type: 'invalid_input',
97
+ userId,
98
+ details: { error: 'Invalid user ID format' },
99
+ });
100
+ return false;
101
+ }
102
+
103
+ if (!RBACSecurityValidator.validatePermission(permission)) {
104
+ RBACSecurityValidator.logSecurityEvent({
105
+ type: 'invalid_input',
106
+ userId,
107
+ details: { error: 'Invalid permission format', permission },
108
+ });
109
+ return false;
110
+ }
111
+
112
+ if (!RBACSecurityValidator.validateScope(scope)) {
113
+ RBACSecurityValidator.logSecurityEvent({
114
+ type: 'invalid_input',
115
+ userId,
116
+ details: { error: 'Invalid scope format', scope },
117
+ });
118
+ return false;
119
+ }
120
+ }
121
+ // 1) If GlobalRole == 'super_admin' → allow (log bypass:true)
122
+ const isSuperAdmin = await this.checkSuperAdmin(userId);
123
+ if (isSuperAdmin) {
124
+ const duration = Date.now() - startTime;
125
+ // Only emit audit event if we have a valid organisation ID
126
+ if (scope.organisationId) {
127
+ // Resolve pageId to UUID if it's a page name
128
+ const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
129
+ await emitAuditEvent({
130
+ type: 'permission_check',
131
+ userId,
132
+ organisationId: scope.organisationId,
133
+ eventId: scope.eventId,
134
+ appId: scope.appId,
135
+ pageId: resolvedPageId,
136
+ permission,
137
+ decision: true,
138
+ source: 'api',
139
+ bypass: true,
140
+ duration_ms: duration,
141
+ });
142
+ }
143
+ return true;
144
+ }
145
+
146
+ // 2) Validate context requirements based on app configuration
147
+ const validatedScope = await this.validateContextRequirements(scope, scope.appId);
148
+ if (!validatedScope) {
149
+ const duration = Date.now() - startTime;
150
+ // Only emit audit event if we have a valid organisation ID
151
+ if (scope.organisationId) {
152
+ // Resolve pageId to UUID if it's a page name
153
+ const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
154
+ await emitAuditEvent({
155
+ type: 'permission_denied',
156
+ userId,
157
+ organisationId: scope.organisationId,
158
+ eventId: scope.eventId,
159
+ appId: scope.appId,
160
+ pageId: resolvedPageId,
161
+ permission,
162
+ source: 'api',
163
+ metadata: {
164
+ reason: 'invalid_context_requirements',
165
+ app_requires_event: scope.appId ? await this.getAppConfig(scope.appId).then(config => config?.requires_event) : null
166
+ }
167
+ });
168
+ }
169
+ return false;
170
+ }
171
+
172
+ // 3) Collect active grants at page → eventApp → organisation → global
173
+ const grants = await this.collectActiveGrants(userId, validatedScope, pageId);
174
+ console.log('[RBACEngine] Collected grants:', grants);
175
+
176
+ // 4) Apply explicit denies at the closest scope first (deny overrides allow)
177
+ const denies = grants.filter(g => g.type === 'deny');
178
+ console.log('[RBACEngine] Deny grants:', denies);
179
+ for (const deny of denies) {
180
+ const matches = this.permissionMatches(deny.permission, permission);
181
+ console.log('[RBACEngine] Checking deny:', {
182
+ denyPermission: deny.permission,
183
+ requestedPermission: permission,
184
+ matches
185
+ });
186
+ if (matches) {
187
+ const duration = Date.now() - startTime;
188
+ console.log('[RBACEngine] Permission DENIED by explicit deny rule');
189
+ // Only emit audit event if we have a valid organisation ID
190
+ if (scope.organisationId) {
191
+ // Resolve pageId to UUID if it's a page name
192
+ const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
193
+ await emitAuditEvent({
194
+ type: 'permission_denied',
195
+ userId,
196
+ organisationId: scope.organisationId,
197
+ eventId: scope.eventId,
198
+ appId: scope.appId,
199
+ pageId: resolvedPageId,
200
+ permission,
201
+ source: 'api',
202
+ });
203
+ }
204
+ return false;
205
+ }
206
+ }
207
+
208
+ // 5) If no deny, check allows from closest to widest scope
209
+ const allows = grants.filter(g => g.type === 'allow');
210
+ console.log('[RBACEngine] Allow grants:', allows);
211
+ let hasPermission = false;
212
+
213
+ // Check allows in precedence order: page → eventApp → organisation → global
214
+ const scopeOrder: Array<'page' | 'eventApp' | 'organisation' | 'global'> = ['page', 'eventApp', 'organisation', 'global'];
215
+
216
+ for (const scopeType of scopeOrder) {
217
+ const scopeAllows = allows.filter(g => g.scope === scopeType);
218
+ console.log(`[RBACEngine] Checking ${scopeType} allows:`, scopeAllows);
219
+ for (const allow of scopeAllows) {
220
+ console.log(`[RBACEngine] About to check permission match for ${scopeType}:`, {
221
+ allowPermission: allow.permission,
222
+ requestedPermission: permission,
223
+ scopeType
224
+ });
225
+ const matches = this.permissionMatches(allow.permission, permission);
226
+ console.log(`[RBACEngine] Permission match result:`, {
227
+ scopeType,
228
+ allowPermission: allow.permission,
229
+ requestedPermission: permission,
230
+ matches
231
+ });
232
+ if (matches) {
233
+ console.log(`[RBACEngine] Permission GRANTED by ${scopeType} allow rule`);
234
+ hasPermission = true;
235
+ break;
236
+ }
237
+ }
238
+ if (hasPermission) break;
239
+ }
240
+
241
+ // 6) Return final decision; emit audit event
242
+ const finalDecision = hasPermission;
243
+ const _duration = Date.now() - startTime;
244
+
245
+ console.log('[RBACEngine] Final decision:', {
246
+ userId,
247
+ permission,
248
+ pageId,
249
+ hasPermission,
250
+ grantsCount: grants.length,
251
+ allowsCount: allows.length,
252
+ deniesCount: denies.length,
253
+ duration: _duration
254
+ });
255
+
256
+ // Only emit audit event if we have a valid organisation ID
257
+ if (scope.organisationId) {
258
+ // Resolve pageId to UUID if it's a page name
259
+ const resolvedPageId = await this.resolvePageId(pageId, scope.appId);
260
+ await emitAuditEvent({
261
+ type: 'permission_check',
262
+ userId,
263
+ organisationId: scope.organisationId,
264
+ eventId: scope.eventId,
265
+ appId: scope.appId,
266
+ pageId: resolvedPageId,
267
+ permission,
268
+ decision: finalDecision,
269
+ source: 'api',
270
+ duration_ms: _duration,
271
+ });
272
+ }
273
+
274
+ return finalDecision;
275
+ } catch (error) {
276
+ // Log security event for unexpected errors
277
+ RBACSecurityValidator.logSecurityEvent({
278
+ type: 'suspicious_activity',
279
+ userId,
280
+ details: {
281
+ error: error instanceof Error ? error.message : 'Unknown error',
282
+ permission,
283
+ scope: JSON.stringify(scope)
284
+ },
285
+ });
286
+
287
+ // Permission check failed - error logged via RBAC logger
288
+ return false;
289
+ }
290
+ }
291
+
292
+ /**
293
+ * Get user's access level in a scope
294
+ *
295
+ * @param input - Access level input
296
+ * @returns Promise resolving to access level
297
+ */
298
+ async getAccessLevel(input: { userId: UUID; scope: Scope }): Promise<AccessLevel> {
299
+ const { userId, scope } = input;
300
+
301
+ // Check super admin first - super admins don't need context validation
302
+ const isSuperAdmin = await this.checkSuperAdmin(userId);
303
+ if (isSuperAdmin) {
304
+ return 'super';
305
+ }
306
+
307
+ // Validate context requirements based on app configuration
308
+ const validatedScope = await this.validateContextRequirements(scope, scope.appId);
309
+ if (!validatedScope) {
310
+ return 'viewer'; // Default to lowest access level for invalid context
311
+ }
312
+
313
+ // Check cache first
314
+ const cacheKey = RBACCache.generateAccessLevelKey(
315
+ userId,
316
+ validatedScope.organisationId!,
317
+ validatedScope.eventId,
318
+ validatedScope.appId
319
+ );
320
+
321
+ const cached = rbacCache.get<AccessLevel>(cacheKey);
322
+ if (cached) {
323
+ return cached;
324
+ }
325
+
326
+ // Check organisation role
327
+ const orgRole = await this.getOrganisationRole(userId, validatedScope.organisationId!);
328
+ if (orgRole === 'org_admin') {
329
+ rbacCache.set(cacheKey, 'admin');
330
+ return 'admin';
331
+ }
332
+
333
+ // Check event-app role
334
+ if (validatedScope.eventId && validatedScope.appId) {
335
+ const eventRole = await this.getEventAppRole(userId, validatedScope.eventId, validatedScope.appId);
336
+ if (eventRole === 'event_admin') {
337
+ rbacCache.set(cacheKey, 'admin');
338
+ return 'admin';
339
+ }
340
+ if (eventRole === 'planner') {
341
+ rbacCache.set(cacheKey, 'planner');
342
+ return 'planner';
343
+ }
344
+ if (eventRole === 'participant') {
345
+ rbacCache.set(cacheKey, 'participant');
346
+ return 'participant';
347
+ }
348
+ }
349
+
350
+ // Default to viewer
351
+ rbacCache.set(cacheKey, 'viewer');
352
+ return 'viewer';
353
+ }
354
+
355
+ /**
356
+ * Get user's permission map for a scope
357
+ *
358
+ * @param input - Permission map input
359
+ * @returns Promise resolving to permission map
360
+ */
361
+ async getPermissionMap(input: { userId: UUID; scope: Scope }): Promise<PermissionMap> {
362
+ const { userId, scope } = input;
363
+
364
+ // Check super admin first - super admins have all permissions
365
+ const isSuperAdmin = await this.checkSuperAdmin(userId);
366
+ if (isSuperAdmin) {
367
+ return {}; // Super admins have all permissions, return empty map
368
+ }
369
+
370
+ // Validate context requirements based on app configuration
371
+ const validatedScope = await this.validateContextRequirements(scope, scope.appId);
372
+ if (!validatedScope) {
373
+ return {}; // No permissions without valid context
374
+ }
375
+
376
+ // Check cache first
377
+ const cacheKey = RBACCache.generatePermissionMapKey(
378
+ userId,
379
+ validatedScope.organisationId!,
380
+ validatedScope.eventId,
381
+ validatedScope.appId
382
+ );
383
+
384
+ const cached = rbacCache.get<PermissionMap>(cacheKey);
385
+ if (cached) {
386
+ return cached;
387
+ }
388
+
389
+ const permissionMap: PermissionMap = {};
390
+
391
+ // Get all pages for the app
392
+ if (validatedScope.appId) {
393
+ const { data: pages } = await this.supabase
394
+ .from('rbac_app_pages')
395
+ .select('id, page_name')
396
+ .eq('app_id', validatedScope.appId) as { data: Array<{ id: string; page_name: string }> | null };
397
+
398
+ if (pages) {
399
+ for (const page of pages) {
400
+ const operations: Operation[] = [];
401
+
402
+ // Check each operation
403
+ for (const operation of ['read', 'create', 'update', 'delete', 'manage'] as Operation[]) {
404
+ const hasPermission = await this.isPermitted({
405
+ userId,
406
+ scope: validatedScope,
407
+ permission: `${operation}:${page.page_name}`,
408
+ pageId: page.id,
409
+ });
410
+
411
+ if (hasPermission) {
412
+ operations.push(operation);
413
+ }
414
+ }
415
+
416
+ permissionMap[page.id] = operations;
417
+ }
418
+ }
419
+ }
420
+
421
+ rbacCache.set(cacheKey, permissionMap);
422
+ return permissionMap;
423
+ }
424
+
425
+ /**
426
+ * Check if user is super admin
427
+ *
428
+ * @param userId - User ID
429
+ * @returns Promise resolving to super admin status
430
+ */
431
+ private async checkSuperAdmin(userId: UUID): Promise<boolean> {
432
+ // Check cache first
433
+ const cacheKey = `super_admin:${userId}`;
434
+ const cached = rbacCache.get<boolean>(cacheKey);
435
+ if (cached !== null) {
436
+ return cached;
437
+ }
438
+
439
+ const { data, error } = await this.supabase
440
+ .from('rbac_global_roles')
441
+ .select('id')
442
+ .eq('user_id', userId)
443
+ .eq('role', 'super_admin')
444
+ .is('valid_to', null)
445
+ .single();
446
+
447
+ const isSuperAdmin = !error && !!data;
448
+
449
+ // Cache the result for 60 seconds
450
+ rbacCache.set(cacheKey, isSuperAdmin, 60000);
451
+
452
+ return isSuperAdmin;
453
+ }
454
+
455
+ /**
456
+ * Get app configuration including requires_event setting
457
+ *
458
+ * @param appId - App ID
459
+ * @returns Promise resolving to app configuration
460
+ */
461
+ async getAppConfig(appId: UUID): Promise<{ requires_event: boolean } | null> {
462
+ const { data, error } = await this.supabase
463
+ .from('rbac_apps')
464
+ .select('requires_event')
465
+ .eq('id', appId)
466
+ .eq('is_active', true)
467
+ .single() as { data: { requires_event: boolean } | null; error: any };
468
+
469
+ if (error || !data) {
470
+ return null;
471
+ }
472
+
473
+ return { requires_event: data.requires_event };
474
+ }
475
+
476
+ /**
477
+ * Resolve organisation ID from event ID
478
+ *
479
+ * @param eventId - Event ID
480
+ * @returns Promise resolving to organisation ID
481
+ */
482
+ private async resolveOrganisationFromEvent(eventId: string): Promise<UUID | null> {
483
+ const { data, error } = await this.supabase
484
+ .from('event')
485
+ .select('organisation_id')
486
+ .eq('id', eventId)
487
+ .single() as { data: { organisation_id: string } | null; error: any };
488
+
489
+ if (error || !data) {
490
+ return null;
491
+ }
492
+
493
+ return data.organisation_id;
494
+ }
495
+
496
+ /**
497
+ * Validate context requirements based on app configuration
498
+ *
499
+ * @param scope - Permission scope
500
+ * @param appId - Optional app ID
501
+ * @returns Promise resolving to validated scope with resolved organisation ID
502
+ */
503
+ private async validateContextRequirements(scope: Scope, appId?: UUID): Promise<Scope | null> {
504
+ // If we have an app ID, check its requirements
505
+ if (appId) {
506
+ const appConfig = await this.getAppConfig(appId);
507
+ if (!appConfig) {
508
+ return null; // App not found or inactive
509
+ }
510
+
511
+ if (appConfig.requires_event) {
512
+ // Event-based app: requires eventId, organisationId is resolved from event
513
+ if (!scope.eventId) {
514
+ return null; // Event context required
515
+ }
516
+
517
+ // Resolve organisation from event if not provided
518
+ if (!scope.organisationId) {
519
+ const resolvedOrgId = await this.resolveOrganisationFromEvent(scope.eventId);
520
+ if (!resolvedOrgId) {
521
+ return null; // Could not resolve organisation from event
522
+ }
523
+ return {
524
+ ...scope,
525
+ organisationId: resolvedOrgId
526
+ };
527
+ }
528
+
529
+ return scope;
530
+ } else {
531
+ // Organisation-based app: requires organisationId, eventId is optional
532
+ if (!scope.organisationId) {
533
+ return null; // Organisation context required
534
+ }
535
+
536
+ return scope;
537
+ }
538
+ }
539
+
540
+ // No app ID provided - use legacy validation (require organisation)
541
+ if (!scope.organisationId) {
542
+ return null; // Organisation context required for legacy behavior
543
+ }
544
+
545
+ return scope;
546
+ }
547
+
548
+ /**
549
+ * Collect active grants for a user in a scope
550
+ *
551
+ * @param userId - User ID
552
+ * @param scope - Permission scope
553
+ * @param pageId - Optional page ID
554
+ * @returns Promise resolving to grants array
555
+ *
556
+ * PRECEDENCE ORDER (closest scope first): page → eventApp → organisation → global
557
+ */
558
+ private async collectActiveGrants(
559
+ userId: UUID,
560
+ scope: Scope,
561
+ pageId?: UUID | string
562
+ ): Promise<Grant[]> {
563
+ const grants: Grant[] = [];
564
+ const now = new Date().toISOString();
565
+
566
+ // Pre-fetch user roles once (to avoid duplicate queries)
567
+ const userRoles: string[] = [];
568
+
569
+ // Get event-app roles
570
+ if (scope.eventId && scope.appId) {
571
+ const { data: eventRoles } = await this.supabase
572
+ .from('rbac_event_app_roles')
573
+ .select('role, status, valid_from, valid_to')
574
+ .eq('user_id', userId)
575
+ .eq('event_id', scope.eventId)
576
+ .eq('app_id', scope.appId)
577
+ .eq('status', 'active')
578
+ .lte('valid_from', now)
579
+ .or(`valid_to.is.null,valid_to.gte.${now}`) as { data: Array<{ role: string; status: string; valid_from: string; valid_to: string | null }> | null };
580
+
581
+ if (eventRoles) {
582
+ userRoles.push(...eventRoles.map(r => r.role));
583
+ // Also add event-app grants
584
+ for (const role of eventRoles) {
585
+ grants.push({
586
+ type: 'allow',
587
+ permission: this.getPermissionForEventRole(role.role as EventAppRole),
588
+ scope: 'eventApp',
589
+ source: 'rbac_event_app_roles',
590
+ });
591
+ }
592
+ }
593
+ }
594
+
595
+ // Get organisation roles
596
+ if (scope.organisationId) {
597
+ const { data: orgRoles } = await this.supabase
598
+ .from('rbac_organisation_roles')
599
+ .select('role, status, valid_from, valid_to')
600
+ .eq('user_id', userId)
601
+ .eq('organisation_id', scope.organisationId)
602
+ .eq('status', 'active')
603
+ .lte('valid_from', now)
604
+ .or(`valid_to.is.null,valid_to.gte.${now}`) as { data: Array<{ role: string; status: string; valid_from: string; valid_to: string | null }> | null };
605
+
606
+ if (orgRoles) {
607
+ userRoles.push(...orgRoles.map(r => r.role));
608
+ // Also add org grants
609
+ for (const role of orgRoles) {
610
+ grants.push({
611
+ type: 'allow',
612
+ permission: this.getPermissionForOrgRole(role.role as OrganisationRole),
613
+ scope: 'organisation',
614
+ source: 'rbac_organisation_roles',
615
+ });
616
+ }
617
+ }
618
+ }
619
+
620
+ console.log('[collectActiveGrants] User roles:', userRoles);
621
+
622
+ // 1. PAGE GRANTS (closest scope first) - Use RPC to bypass RLS
623
+ if (pageId) {
624
+ // Resolve page ID if it's a page name (string)
625
+ let resolvedPageId: UUID | null = null;
626
+ if (typeof pageId === 'string') {
627
+ // Check if it's already a UUID
628
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
629
+ if (uuidRegex.test(pageId)) {
630
+ resolvedPageId = pageId as UUID;
631
+ } else {
632
+ // It's a page name, resolve it to a page ID
633
+ const appId = scope.appId;
634
+ if (appId) {
635
+ const { data: page } = await this.supabase
636
+ .from('rbac_app_pages')
637
+ .select('id')
638
+ .eq('app_id', appId)
639
+ .eq('page_name', pageId)
640
+ .single() as { data: { id: UUID } | null };
641
+ resolvedPageId = page?.id || null;
642
+ }
643
+ }
644
+ } else {
645
+ resolvedPageId = pageId;
646
+ }
647
+
648
+ if (resolvedPageId && scope.appId) {
649
+ console.log('[collectActiveGrants] Fetching page permissions via RPC for page:', resolvedPageId);
650
+
651
+ // Get the page name for building specific permission strings
652
+ let pageName: string | null = null;
653
+ if (typeof pageId === 'string' && !/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(pageId)) {
654
+ // pageId is already the page name
655
+ pageName = pageId;
656
+ } else {
657
+ // Fetch page name from database
658
+ const { data: page } = await this.supabase
659
+ .from('rbac_app_pages')
660
+ .select('page_name')
661
+ .eq('id', resolvedPageId)
662
+ .single() as { data: { page_name: string } | null };
663
+ pageName = page?.page_name || null;
664
+ }
665
+
666
+ // Use RPC to get page permissions (bypasses RLS)
667
+ // @ts-ignore - RPC type inference is incorrect
668
+ const rpcResult = await this.supabase.rpc('get_rbac_permissions', {
669
+ p_user_id: userId,
670
+ p_app_id: scope.appId,
671
+ p_event_id: scope.eventId || null,
672
+ p_organisation_id: scope.organisationId || null,
673
+ p_page_id: resolvedPageId
674
+ });
675
+
676
+ const { data: rpcPermissions } = rpcResult as { data: Array<{ permission_type: string; role_name: string; has_permission: boolean }> | null; error: any };
677
+
678
+ console.log('[collectActiveGrants] RPC page permissions:', rpcPermissions);
679
+
680
+ if (rpcPermissions && pageName) {
681
+ // Filter to only page-level permissions (not org/event-app roles)
682
+ const pagePerms = rpcPermissions.filter(p =>
683
+ p.permission_type !== 'all_permissions' &&
684
+ p.permission_type !== 'organisation_access' &&
685
+ p.permission_type !== 'event_app_access'
686
+ );
687
+
688
+ for (const perm of pagePerms) {
689
+ // Only add if user has this role
690
+ if (userRoles.includes(perm.role_name)) {
691
+ console.log('[collectActiveGrants] Adding page grant:', { operation: perm.permission_type, role: perm.role_name, allowed: perm.has_permission, pageName });
692
+ grants.push({
693
+ type: perm.has_permission ? 'allow' : 'deny',
694
+ // Use page.${pageName} format for specific page permissions
695
+ permission: `${perm.permission_type}:page.${pageName}` as Permission,
696
+ scope: 'page',
697
+ source: 'rbac_page_permissions',
698
+ });
699
+ }
700
+ }
701
+ }
702
+ }
703
+ }
704
+
705
+ // 2. GLOBAL GRANTS (widest scope last)
706
+ const { data: globalRoles } = await this.supabase
707
+ .from('rbac_global_roles')
708
+ .select('role, valid_from, valid_to')
709
+ .eq('user_id', userId)
710
+ .lte('valid_from', now)
711
+ .or(`valid_to.is.null,valid_to.gte.${now}`) as { data: Array<{ role: string; valid_from: string; valid_to: string | null }> | null };
712
+
713
+ if (globalRoles) {
714
+ for (const role of globalRoles) {
715
+ if (role.role === 'super_admin') {
716
+ grants.push({
717
+ type: 'allow',
718
+ permission: 'manage:*' as Permission,
719
+ scope: 'global',
720
+ source: 'rbac_global_roles',
721
+ });
722
+ }
723
+ }
724
+ }
725
+
726
+ console.log('[collectActiveGrants] Final grants:', grants);
727
+
728
+ return grants;
729
+ }
730
+
731
+ /**
732
+ * Check page-specific permissions
733
+ *
734
+ * @param userId - User ID
735
+ * @param pageId - Page ID
736
+ * @param permission - Permission to check
737
+ * @param scope - Permission scope
738
+ * @returns Promise resolving to page permission result
739
+ */
740
+ private async checkPagePermissions(
741
+ userId: UUID,
742
+ pageId: UUID | string | undefined,
743
+ permission: Permission,
744
+ scope: Scope
745
+ ): Promise<boolean> {
746
+ if (!pageId) {
747
+ return true; // No page restrictions
748
+ }
749
+
750
+ const [operation] = permission.split(':') as [Operation, string];
751
+
752
+ // Get user's roles in this scope
753
+ const userRoles: string[] = [];
754
+
755
+ // Add organisation role
756
+ if (scope.organisationId) {
757
+ const orgRole = await this.getOrganisationRole(userId, scope.organisationId);
758
+ if (orgRole) {
759
+ userRoles.push(orgRole);
760
+ }
761
+ }
762
+
763
+ // Add event-app role
764
+ if (scope.eventId && scope.appId) {
765
+ const eventRole = await this.getEventAppRole(userId, scope.eventId, scope.appId);
766
+ if (eventRole) {
767
+ userRoles.push(eventRole);
768
+ }
769
+ }
770
+
771
+ // Resolve page ID if it's a page name (string)
772
+ let resolvedPageId: UUID | null = null;
773
+ if (typeof pageId === 'string') {
774
+ // Check if it's already a UUID
775
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
776
+ if (uuidRegex.test(pageId)) {
777
+ resolvedPageId = pageId as UUID;
778
+ } else {
779
+ // It's a page name, resolve it to a page ID
780
+ // First, get the app ID from scope or environment
781
+ let appId = scope.appId;
782
+ if (!appId) {
783
+ // Try to get app ID from environment
784
+ const appName = process.env.VITE_APP_NAME || process.env.REACT_APP_NAME;
785
+ if (appName) {
786
+ const { data: app } = await this.supabase
787
+ .from('rbac_apps')
788
+ .select('id')
789
+ .eq('name', appName)
790
+ .eq('is_active', true)
791
+ .single() as { data: { id: UUID } | null };
792
+ if (app) {
793
+ appId = app.id;
794
+ }
795
+ }
796
+ }
797
+
798
+ if (appId) {
799
+ const { data: page } = await this.supabase
800
+ .from('rbac_app_pages')
801
+ .select('id')
802
+ .eq('app_id', appId)
803
+ .eq('page_name', pageId)
804
+ .single() as { data: { id: UUID } | null };
805
+ resolvedPageId = page?.id || null;
806
+ }
807
+ }
808
+ } else {
809
+ resolvedPageId = pageId;
810
+ }
811
+
812
+ if (!resolvedPageId) {
813
+ return false; // Page not found
814
+ }
815
+
816
+ // Check page permissions
817
+ const { data: pagePermissions } = await this.supabase
818
+ .from('rbac_page_permissions')
819
+ .select('allowed')
820
+ .eq('app_page_id', resolvedPageId)
821
+ .eq('operation', operation)
822
+ .in('role_name', userRoles)
823
+ .single() as { data: { allowed: boolean } | null };
824
+
825
+ return pagePermissions?.allowed ?? false;
826
+ }
827
+
828
+ /**
829
+ * Get organisation role for a user
830
+ *
831
+ * @param userId - User ID
832
+ * @param organisationId - Organisation ID
833
+ * @returns Promise resolving to organisation role
834
+ */
835
+ private async getOrganisationRole(userId: UUID, organisationId: UUID): Promise<OrganisationRole | null> {
836
+ const { data, error } = await this.supabase
837
+ .from('rbac_organisation_roles')
838
+ .select('role')
839
+ .eq('user_id', userId)
840
+ .eq('organisation_id', organisationId)
841
+ .eq('status', 'active')
842
+ .single() as { data: { role: string } | null; error: any };
843
+
844
+ return error ? null : (data?.role as OrganisationRole) || null;
845
+ }
846
+
847
+ /**
848
+ * Get event-app role for a user
849
+ *
850
+ * @param userId - User ID
851
+ * @param eventId - Event ID
852
+ * @param appId - App ID
853
+ * @returns Promise resolving to event-app role
854
+ */
855
+ private async getEventAppRole(userId: UUID, eventId: string, appId: UUID): Promise<EventAppRole | null> {
856
+ const { data, error } = await this.supabase
857
+ .from('rbac_event_app_roles')
858
+ .select('role, status, valid_from, valid_to')
859
+ .eq('user_id', userId)
860
+ .eq('event_id', eventId)
861
+ .eq('app_id', appId)
862
+ .eq('status', 'active')
863
+ .lte('valid_from', new Date().toISOString())
864
+ .or(`valid_to.is.null,valid_to.gte.${new Date().toISOString()}`)
865
+ .single() as { data: { role: string; status: string; valid_from: string; valid_to: string | null } | null; error: any };
866
+
867
+ return error ? null : (data?.role as EventAppRole) || null;
868
+ }
869
+
870
+ /**
871
+ * Get permission for organisation role
872
+ *
873
+ * @param role - Organisation role
874
+ * @returns Permission string
875
+ */
876
+ private getPermissionForOrgRole(role: OrganisationRole): Permission {
877
+ switch (role) {
878
+ case 'org_admin':
879
+ return 'manage:*' as Permission;
880
+ case 'leader':
881
+ return 'manage:organisation.*' as Permission;
882
+ case 'member':
883
+ return 'read:organisation.*' as Permission;
884
+ case 'supporter':
885
+ return 'read:organisation.public' as Permission;
886
+ default:
887
+ return 'read:organisation.public' as Permission;
888
+ }
889
+ }
890
+
891
+ /**
892
+ * Get permission for event-app role
893
+ *
894
+ * @param role - Event-app role
895
+ * @returns Permission string
896
+ */
897
+ private getPermissionForEventRole(role: EventAppRole): Permission {
898
+ switch (role) {
899
+ case 'event_admin':
900
+ return 'manage:event.*' as Permission;
901
+ case 'planner':
902
+ return 'manage:event.planning' as Permission;
903
+ case 'participant':
904
+ return 'read:event.*' as Permission;
905
+ case 'viewer':
906
+ return 'read:event.public' as Permission;
907
+ default:
908
+ return 'read:event.public' as Permission;
909
+ }
910
+ }
911
+
912
+ /**
913
+ * Check if a permission matches another permission
914
+ *
915
+ * @param grantPermission - Permission from grant
916
+ * @param requestedPermission - Requested permission
917
+ * @returns True if permissions match
918
+ */
919
+ private permissionMatches(grantPermission: Permission, requestedPermission: Permission): boolean {
920
+ console.log('[permissionMatches] Checking:', { grantPermission, requestedPermission });
921
+
922
+ // Exact match
923
+ if (grantPermission === requestedPermission) {
924
+ console.log('[permissionMatches] Exact match found');
925
+ return true;
926
+ }
927
+
928
+ // Wildcard match
929
+ if (grantPermission.endsWith(':*') || grantPermission.endsWith('.*')) {
930
+ const [grantOp, grantResource] = grantPermission.split(':');
931
+ const [requestedOp, requestedResource] = requestedPermission.split(':');
932
+
933
+ console.log('[permissionMatches] Wildcard check:', {
934
+ grantOp,
935
+ grantResource,
936
+ requestedOp,
937
+ requestedResource,
938
+ operationsMatch: grantOp === requestedOp
939
+ });
940
+
941
+ if (grantOp === requestedOp) {
942
+ // For wildcard permissions like "read:*" or "read:organisation.*", grantResource is "*" or "organisation.*"
943
+ // We need to check if the requested resource starts with the prefix before "*"
944
+ const prefix = grantResource.slice(0, -1); // Remove the "*"
945
+ const matches = prefix === '' || requestedResource.startsWith(prefix);
946
+ console.log('[permissionMatches] Wildcard match result:', { prefix, matches });
947
+ return matches;
948
+ }
949
+ }
950
+
951
+ // Check for other wildcard patterns
952
+ if (grantPermission.includes('*')) {
953
+ const [grantOp, grantResource] = grantPermission.split(':');
954
+ const [requestedOp, requestedResource] = requestedPermission.split(':');
955
+
956
+ console.log('[permissionMatches] Other wildcard check:', {
957
+ grantOp,
958
+ grantResource,
959
+ requestedOp,
960
+ requestedResource,
961
+ operationsMatch: grantOp === requestedOp
962
+ });
963
+
964
+ if (grantOp === requestedOp) {
965
+ // For wildcard permissions like "read:event*", grantResource is "event*"
966
+ const prefix = grantResource.replace('*', '');
967
+ const matches = requestedResource.startsWith(prefix);
968
+ console.log('[permissionMatches] Other wildcard match result:', { prefix, matches });
969
+ return matches;
970
+ }
971
+ }
972
+
973
+ console.log('[permissionMatches] No match found');
974
+ return false;
975
+ }
976
+
977
+ /**
978
+ * Resolve a page ID to UUID if it's a page name
979
+ *
980
+ * @param pageId - Page ID (UUID) or page name (string)
981
+ * @param appId - App ID to look up the page
982
+ * @returns Resolved page ID (UUID) or original pageId if it's already a UUID or can't be resolved
983
+ */
984
+ private async resolvePageId(pageId?: UUID | string, appId?: UUID): Promise<UUID | string | undefined> {
985
+ if (!pageId) {
986
+ return undefined;
987
+ }
988
+
989
+ // Check if it's already a UUID
990
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
991
+ if (uuidRegex.test(pageId)) {
992
+ return pageId as UUID;
993
+ }
994
+
995
+ // It's a page name, but we need appId to resolve it
996
+ if (!appId) {
997
+ // If we can't resolve it, return the original value
998
+ return pageId;
999
+ }
1000
+
1001
+ // It's a page name, resolve it to a page ID
1002
+ try {
1003
+ const { data: page } = await this.supabase
1004
+ .from('rbac_app_pages')
1005
+ .select('id')
1006
+ .eq('app_id', appId)
1007
+ .eq('page_name', pageId)
1008
+ .single() as { data: { id: UUID } | null };
1009
+
1010
+ return page?.id || pageId; // Return original if not found
1011
+ } catch (error) {
1012
+ console.warn('[RBAC Engine] Failed to resolve page name to UUID:', { pageId, appId, error });
1013
+ return pageId; // Return original on error
1014
+ }
1015
+ }
1016
+ }
1017
+
1018
+ /**
1019
+ * Create an RBAC engine instance
1020
+ *
1021
+ * @param supabase - Supabase client
1022
+ * @returns RBACEngine instance
1023
+ */
1024
+ export function createRBACEngine(supabase: SupabaseClient<Database>): RBACEngine {
1025
+ return new RBACEngine(supabase);
1026
+ }