@jmruthers/pace-core 0.5.135 → 0.5.137

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 (544) hide show
  1. package/dist/{DataTable-A36PJG6N.js → DataTable-6M4L6BI2.js} +26 -13
  2. package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
  3. package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-rFL_kRjk.d.ts} +123 -135
  4. package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
  5. package/dist/{UnifiedAuthProvider-CQDZRJIS.js → UnifiedAuthProvider-XIQQ7LVU.js} +5 -5
  6. package/dist/{api-TNIBJWLM.js → api-45XYYO2A.js} +4 -3
  7. package/dist/{audit-T36HM7IM.js → audit-64X3VJXB.js} +3 -2
  8. package/dist/{chunk-F64FFPOZ.js → chunk-22WKWKRX.js} +26 -20
  9. package/dist/chunk-22WKWKRX.js.map +1 -0
  10. package/dist/{chunk-VZ5OR6HD.js → chunk-4C7EXCAR.js} +62 -150
  11. package/dist/chunk-4C7EXCAR.js.map +1 -0
  12. package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
  13. package/dist/chunk-56XJ3TU6.js.map +1 -0
  14. package/dist/{chunk-CTJRBUX2.js → chunk-6LAAY47Q.js} +2 -2
  15. package/dist/{chunk-UJI6WSMD.js → chunk-7QCC6MCP.js} +90 -3
  16. package/dist/chunk-7QCC6MCP.js.map +1 -0
  17. package/dist/{chunk-66C4BSAY.js → chunk-ANBQRTPX.js} +9 -2
  18. package/dist/chunk-ANBQRTPX.js.map +1 -0
  19. package/dist/{chunk-CQZU6TFE.js → chunk-BCIBECNB.js} +100 -62
  20. package/dist/chunk-BCIBECNB.js.map +1 -0
  21. package/dist/{chunk-GKHF54DI.js → chunk-BESYRHQM.js} +10 -4
  22. package/dist/chunk-BESYRHQM.js.map +1 -0
  23. package/dist/chunk-BJPBT3CU.js +21 -0
  24. package/dist/chunk-BJPBT3CU.js.map +1 -0
  25. package/dist/{chunk-BYXRHAIF.js → chunk-BLCXZEYF.js} +23 -14
  26. package/dist/chunk-BLCXZEYF.js.map +1 -0
  27. package/dist/{chunk-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
  28. package/dist/chunk-BVYWGZVV.js.map +1 -0
  29. package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
  30. package/dist/chunk-ERISIBYU.js.map +1 -0
  31. package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
  32. package/dist/chunk-FMUCXFII.js.map +1 -0
  33. package/dist/{chunk-GVDR7WNV.js → chunk-HAWZXGR2.js} +334 -614
  34. package/dist/chunk-HAWZXGR2.js.map +1 -0
  35. package/dist/{chunk-ZV77RZMU.js → chunk-INQLMHPF.js} +2 -2
  36. package/dist/chunk-JISYG63F.js +70 -0
  37. package/dist/chunk-JISYG63F.js.map +1 -0
  38. package/dist/{chunk-HMNOSGVA.js → chunk-KYRHUBIU.js} +576 -767
  39. package/dist/chunk-KYRHUBIU.js.map +1 -0
  40. package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
  41. package/dist/chunk-LS353YLY.js.map +1 -0
  42. package/dist/{chunk-TGIY2AR2.js → chunk-MA6EPSGZ.js} +4 -3
  43. package/dist/{chunk-TGIY2AR2.js.map → chunk-MA6EPSGZ.js.map} +1 -1
  44. package/dist/chunk-OWAG3GSU.js +58 -0
  45. package/dist/chunk-OWAG3GSU.js.map +1 -0
  46. package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
  47. package/dist/chunk-Q5QRDWKI.js.map +1 -0
  48. package/dist/chunk-S5OFRT4M.js +94 -0
  49. package/dist/chunk-S5OFRT4M.js.map +1 -0
  50. package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
  51. package/dist/chunk-SBVILCCA.js.map +1 -0
  52. package/dist/{chunk-ZYZCRSBD.js → chunk-T6JN6LH6.js} +16 -11
  53. package/dist/chunk-T6JN6LH6.js.map +1 -0
  54. package/dist/chunk-XDNLUEXI.js +138 -0
  55. package/dist/chunk-XDNLUEXI.js.map +1 -0
  56. package/dist/{chunk-3CG5L6RN.js → chunk-YCWDTTUK.js} +90 -75
  57. package/dist/chunk-YCWDTTUK.js.map +1 -0
  58. package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
  59. package/dist/chunk-ZZ2SS7NI.js.map +1 -0
  60. package/dist/components.d.ts +7 -287
  61. package/dist/components.js +27 -157
  62. package/dist/components.js.map +1 -1
  63. package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
  64. package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
  65. package/dist/hooks.d.ts +3 -3
  66. package/dist/hooks.js +21 -16
  67. package/dist/hooks.js.map +1 -1
  68. package/dist/index.d.ts +101 -9
  69. package/dist/index.js +44 -31
  70. package/dist/index.js.map +1 -1
  71. package/dist/providers.d.ts +1 -1
  72. package/dist/providers.js +4 -4
  73. package/dist/rbac/index.js +12 -12
  74. package/dist/schema-DTDZQe2u.d.ts +28 -0
  75. package/dist/styles/index.js +2 -1
  76. package/dist/theming/runtime.d.ts +2 -19
  77. package/dist/theming/runtime.js +2 -1
  78. package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
  79. package/dist/types.d.ts +153 -4
  80. package/dist/types.js +51 -16
  81. package/dist/types.js.map +1 -1
  82. package/dist/{useInactivityTracker-MRUU55XI.js → useInactivityTracker-TO6ZOF35.js} +3 -2
  83. package/dist/{usePublicRouteParams-Dyt1tzI9.d.ts → usePublicRouteParams-B7PabvuH.d.ts} +1 -1
  84. package/dist/utils.d.ts +221 -173
  85. package/dist/utils.js +185 -225
  86. package/dist/utils.js.map +1 -1
  87. package/dist/validation.d.ts +24 -115
  88. package/dist/validation.js +19 -474
  89. package/dist/validation.js.map +1 -1
  90. package/docs/api/classes/ColumnFactory.md +1 -1
  91. package/docs/api/classes/ErrorBoundary.md +6 -6
  92. package/docs/api/classes/InvalidScopeError.md +1 -1
  93. package/docs/api/classes/MissingUserContextError.md +1 -1
  94. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  95. package/docs/api/classes/PermissionDeniedError.md +1 -1
  96. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  97. package/docs/api/classes/RBACAuditManager.md +6 -6
  98. package/docs/api/classes/RBACCache.md +1 -1
  99. package/docs/api/classes/RBACEngine.md +7 -7
  100. package/docs/api/classes/RBACError.md +1 -1
  101. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  102. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  103. package/docs/api/classes/StorageUtils.md +1 -1
  104. package/docs/api/enums/FileCategory.md +1 -1
  105. package/docs/api/interfaces/AggregateConfig.md +4 -4
  106. package/docs/api/interfaces/BadgeProps.md +27 -0
  107. package/docs/api/interfaces/ButtonProps.md +1 -1
  108. package/docs/api/interfaces/CardProps.md +1 -1
  109. package/docs/api/interfaces/ColorPalette.md +1 -1
  110. package/docs/api/interfaces/ColorShade.md +29 -4
  111. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  112. package/docs/api/interfaces/DataRecord.md +1 -1
  113. package/docs/api/interfaces/DataTableAction.md +18 -18
  114. package/docs/api/interfaces/DataTableColumn.md +61 -1
  115. package/docs/api/interfaces/DataTableProps.md +1 -1
  116. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  117. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  118. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +14 -14
  119. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  120. package/docs/api/interfaces/EventLogoProps.md +152 -0
  121. package/docs/api/interfaces/ExportColumn.md +1 -1
  122. package/docs/api/interfaces/ExportOptions.md +8 -8
  123. package/docs/api/interfaces/FileDisplayProps.md +15 -15
  124. package/docs/api/interfaces/FileMetadata.md +1 -1
  125. package/docs/api/interfaces/FileReference.md +1 -1
  126. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  127. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  128. package/docs/api/interfaces/FileUploadProps.md +1 -1
  129. package/docs/api/interfaces/FooterProps.md +1 -1
  130. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  131. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  132. package/docs/api/interfaces/InputProps.md +1 -1
  133. package/docs/api/interfaces/LabelProps.md +1 -1
  134. package/docs/api/interfaces/LoginFormProps.md +1 -1
  135. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  136. package/docs/api/interfaces/NavigationContextType.md +9 -9
  137. package/docs/api/interfaces/NavigationGuardProps.md +10 -10
  138. package/docs/api/interfaces/NavigationItem.md +1 -1
  139. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  140. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  141. package/docs/api/interfaces/Organisation.md +1 -1
  142. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  143. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  144. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  145. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  146. package/docs/api/interfaces/PaceAppLayoutProps.md +27 -27
  147. package/docs/api/interfaces/PaceLoginPageProps.md +4 -4
  148. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  149. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  150. package/docs/api/interfaces/PagePermissionGuardProps.md +11 -11
  151. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  152. package/docs/api/interfaces/PaletteData.md +4 -4
  153. package/docs/api/interfaces/PermissionEnforcerProps.md +11 -11
  154. package/docs/api/interfaces/ProtectedRouteProps.md +6 -6
  155. package/docs/api/interfaces/PublicErrorBoundaryProps.md +1 -1
  156. package/docs/api/interfaces/PublicErrorBoundaryState.md +1 -1
  157. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +1 -1
  158. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  159. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  160. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  161. package/docs/api/interfaces/RBACConfig.md +1 -1
  162. package/docs/api/interfaces/RBACLogger.md +1 -1
  163. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  164. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  165. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  166. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  167. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  168. package/docs/api/interfaces/RouteConfig.md +10 -10
  169. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  170. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  171. package/docs/api/interfaces/SessionRestorationLoaderProps.md +21 -0
  172. package/docs/api/interfaces/StorageConfig.md +1 -1
  173. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  174. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  175. package/docs/api/interfaces/StorageListOptions.md +1 -1
  176. package/docs/api/interfaces/StorageListResult.md +1 -1
  177. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  178. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  179. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  180. package/docs/api/interfaces/StyleImport.md +1 -1
  181. package/docs/api/interfaces/SwitchProps.md +1 -1
  182. package/docs/api/interfaces/ToastActionElement.md +1 -1
  183. package/docs/api/interfaces/ToastProps.md +1 -1
  184. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  185. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  186. package/docs/api/interfaces/UseInactivityTrackerOptions.md +9 -9
  187. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  188. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  189. package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
  190. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  191. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +9 -9
  192. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  193. package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
  194. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  195. package/docs/api/interfaces/UserEventAccess.md +11 -11
  196. package/docs/api/interfaces/UserMenuProps.md +1 -1
  197. package/docs/api/interfaces/UserProfile.md +1 -1
  198. package/docs/api/modules.md +591 -220
  199. package/docs/api-reference/components.md +106 -26
  200. package/docs/architecture/README.md +0 -3
  201. package/docs/implementation-guides/data-tables.md +277 -13
  202. package/docs/implementation-guides/forms.md +1 -16
  203. package/docs/implementation-guides/permission-enforcement.md +8 -2
  204. package/docs/styles/README.md +0 -2
  205. package/examples/README.md +30 -14
  206. package/examples/STRUCTURE.md +125 -0
  207. package/examples/components 2/DataTable/HierarchicalActionsExample.tsx +421 -0
  208. package/examples/components 2/DataTable/HierarchicalExample.tsx +475 -0
  209. package/examples/components 2/DataTable/InitialPageSizeExample.tsx +177 -0
  210. package/examples/components 2/DataTable/PerformanceExample.tsx +506 -0
  211. package/examples/components 2/DataTable/index.ts +13 -0
  212. package/examples/components 2/Dialog/BasicHtmlTest.tsx +55 -0
  213. package/examples/components 2/Dialog/DebugHtmlExample.tsx +68 -0
  214. package/examples/components 2/Dialog/HtmlDialogExample.tsx +202 -0
  215. package/examples/components 2/Dialog/ScrollableDialogExample.tsx +290 -0
  216. package/examples/components 2/Dialog/SimpleHtmlTest.tsx +61 -0
  217. package/examples/components 2/Dialog/SmartDialogExample.tsx +322 -0
  218. package/examples/components 2/Dialog/index.ts +15 -0
  219. package/examples/components 2/index.ts +11 -0
  220. package/examples/features/index.ts +12 -0
  221. package/{src/examples → examples/features/public-pages}/CorrectPublicPageImplementation.tsx +14 -17
  222. package/{src/examples → examples/features/public-pages}/PublicEventPage.tsx +14 -27
  223. package/{src/examples → examples/features/public-pages}/PublicPageApp.tsx +15 -28
  224. package/{src/examples → examples/features/public-pages}/PublicPageUsageExample.tsx +8 -10
  225. package/examples/features/public-pages/index.ts +14 -0
  226. package/examples/features/rbac/CompleteRBACExample.tsx +324 -0
  227. package/examples/features/rbac/EventBasedApp.tsx +239 -0
  228. package/examples/features/rbac/PermissionExample.tsx +151 -0
  229. package/examples/features/rbac/index.ts +13 -0
  230. package/examples/index.ts +11 -3
  231. package/package.json +30 -19
  232. package/src/__tests__/TEST_STANDARD.md +92 -0
  233. package/src/components/Alert/Alert.tsx +1 -1
  234. package/src/components/Avatar/Avatar.tsx +1 -1
  235. package/src/components/Badge/Badge.test.tsx +314 -0
  236. package/src/components/Badge/Badge.tsx +304 -0
  237. package/src/components/Badge/index.ts +3 -0
  238. package/src/components/Button/Button.tsx +1 -1
  239. package/src/components/Card/Card.tsx +1 -1
  240. package/src/components/Checkbox/Checkbox.tsx +1 -1
  241. package/src/components/DataTable/DataTable.test.tsx +1 -1
  242. package/src/components/DataTable/DataTable.tsx +1 -30
  243. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
  244. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +217 -0
  245. package/src/components/DataTable/__tests__/styles.test.ts +3 -3
  246. package/src/components/DataTable/components/ActionButtons.tsx +0 -15
  247. package/src/components/DataTable/components/ColumnFilter.tsx +8 -4
  248. package/src/components/DataTable/components/DataTableBody.tsx +461 -0
  249. package/src/components/DataTable/components/DataTableCore.tsx +4 -185
  250. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
  251. package/src/components/DataTable/components/DataTableModals.tsx +1 -27
  252. package/src/components/DataTable/components/DraggableColumnHeader.tsx +144 -0
  253. package/src/components/DataTable/components/EditableRow.tsx +1 -1
  254. package/src/components/DataTable/components/FilterRow.tsx +9 -3
  255. package/src/components/DataTable/components/ImportModal.tsx +2 -14
  256. package/src/components/DataTable/components/PaginationControls.tsx +2 -1
  257. package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
  258. package/src/components/DataTable/components/VirtualizedDataTable.tsx +513 -0
  259. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +14 -68
  260. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
  261. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +62 -0
  262. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
  263. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
  264. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +43 -0
  265. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
  266. package/src/components/DataTable/core/ActionManager.ts +235 -0
  267. package/src/components/DataTable/core/ColumnManager.ts +205 -0
  268. package/src/components/DataTable/core/DataManager.ts +188 -0
  269. package/src/components/DataTable/core/DataTableContext.tsx +181 -0
  270. package/src/components/DataTable/core/LocalDataAdapter.ts +273 -0
  271. package/src/components/DataTable/core/PluginRegistry.ts +229 -0
  272. package/src/components/DataTable/core/StateManager.ts +311 -0
  273. package/src/components/DataTable/core/interfaces.ts +338 -0
  274. package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
  275. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
  276. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
  277. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
  278. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
  279. package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
  280. package/src/components/DataTable/index.ts +4 -0
  281. package/src/components/DataTable/styles.ts +28 -7
  282. package/src/components/DataTable/types.ts +13 -0
  283. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +94 -0
  284. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
  285. package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
  286. package/src/components/DataTable/utils/columnUtils.ts +40 -0
  287. package/src/components/DataTable/utils/debugTools.ts +609 -0
  288. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  289. package/src/components/DataTable/utils/flexibleImport.ts +1 -11
  290. package/src/components/DataTable/utils/index.ts +2 -0
  291. package/src/components/DataTable/utils/paginationUtils.ts +1 -1
  292. package/src/components/Dialog/Dialog.tsx +2 -2
  293. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +8 -1
  294. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
  295. package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
  296. package/src/components/EventSelector/EventSelector.tsx +3 -2
  297. package/src/components/FileDisplay/FileDisplay.tsx +2 -36
  298. package/src/components/FileUpload/FileUpload.test.tsx +2 -2
  299. package/src/components/FileUpload/FileUpload.tsx +2 -2
  300. package/src/components/Footer/Footer.test.tsx +1 -1
  301. package/src/components/Footer/Footer.tsx +1 -1
  302. package/src/components/Form/Form.test.tsx +5 -510
  303. package/src/components/Form/Form.tsx +1 -1
  304. package/src/components/Form/FormField.tsx +1 -1
  305. package/src/components/Form/index.ts +0 -12
  306. package/src/components/Header/Header.tsx +1 -1
  307. package/src/components/Input/Input.tsx +1 -1
  308. package/src/components/Label/Label.tsx +1 -1
  309. package/src/components/LoginForm/LoginForm.test.tsx +1 -1
  310. package/src/components/LoginForm/LoginForm.tsx +1 -1
  311. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
  312. package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
  313. package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
  314. package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
  315. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
  316. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.performance.test.tsx +76 -10
  317. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
  318. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
  319. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
  320. package/src/components/PaceLoginPage/PaceLoginPage.tsx +14 -13
  321. package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
  322. package/src/components/PasswordReset/index.ts +0 -2
  323. package/src/components/Progress/Progress.tsx +1 -1
  324. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
  325. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
  326. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  327. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
  328. package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
  329. package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
  330. package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
  331. package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
  332. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
  333. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +1 -1
  334. package/src/components/PublicLayout/index.ts +4 -2
  335. package/src/components/Select/Select.test.tsx +1 -1
  336. package/src/components/Select/Select.tsx +21 -9
  337. package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
  338. package/src/components/SessionRestorationLoader/index.ts +3 -0
  339. package/src/components/Switch/Switch.tsx +1 -1
  340. package/src/components/Table/Table.tsx +1 -1
  341. package/src/components/Table/__tests__/Table.test.tsx +1 -1
  342. package/src/components/Toast/Toast.tsx +1 -1
  343. package/src/components/Tooltip/Tooltip.tsx +1 -1
  344. package/src/components/index.ts +7 -10
  345. package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
  346. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
  347. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
  348. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
  349. package/src/hooks/__tests__/useFileUrl.unit.test.ts +83 -85
  350. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
  351. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
  352. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
  353. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
  354. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
  355. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
  356. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
  357. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
  358. package/src/hooks/public/usePublicEvent.ts +7 -6
  359. package/src/hooks/public/usePublicEventLogo.ts +7 -4
  360. package/src/hooks/public/usePublicFileDisplay.ts +6 -150
  361. package/src/hooks/useComponentPerformance.ts +4 -1
  362. package/src/hooks/useDataTablePerformance.ts +4 -3
  363. package/src/hooks/useEventTheme.test.ts +18 -5
  364. package/src/hooks/useEventTheme.ts +4 -1
  365. package/src/hooks/useEvents.ts +2 -0
  366. package/src/hooks/useFileDisplay.ts +9 -8
  367. package/src/hooks/useFileReference.ts +4 -1
  368. package/src/hooks/useFileUrl.ts +4 -1
  369. package/src/hooks/useInactivityTracker.ts +5 -4
  370. package/src/hooks/useOrganisationSecurity.test.ts +33 -12
  371. package/src/hooks/useOrganisationSecurity.ts +8 -7
  372. package/src/hooks/usePerformanceMonitor.ts +6 -3
  373. package/src/hooks/usePermissionCache.ts +13 -6
  374. package/src/hooks/useSecureDataAccess.test.ts +2 -2
  375. package/src/hooks/useSecureDataAccess.ts +9 -8
  376. package/src/hooks/useSessionRestoration.ts +4 -1
  377. package/src/hooks/useStorage.ts +4 -1
  378. package/src/index.ts +20 -7
  379. package/src/providers/services/AuthServiceProvider.tsx +3 -2
  380. package/src/providers/services/EventServiceProvider.tsx +2 -1
  381. package/src/providers/services/InactivityServiceProvider.tsx +2 -1
  382. package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
  383. package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
  384. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
  385. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
  386. package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
  387. package/src/rbac/api.ts +5 -2
  388. package/src/rbac/audit-enhanced.ts +6 -6
  389. package/src/rbac/audit.test.ts +60 -38
  390. package/src/rbac/audit.ts +8 -8
  391. package/src/rbac/cache-invalidation.ts +7 -4
  392. package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
  393. package/src/rbac/components/NavigationGuard.tsx +7 -3
  394. package/src/rbac/components/NavigationProvider.tsx +6 -3
  395. package/src/rbac/components/PagePermissionGuard.tsx +28 -16
  396. package/src/rbac/components/PagePermissionProvider.tsx +4 -1
  397. package/src/rbac/components/PermissionEnforcer.tsx +9 -3
  398. package/src/rbac/components/RoleBasedRouter.tsx +3 -1
  399. package/src/rbac/components/SecureDataProvider.tsx +7 -3
  400. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
  401. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
  402. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
  403. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
  404. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
  405. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
  406. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
  407. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
  408. package/src/rbac/engine.ts +15 -7
  409. package/src/rbac/hooks/usePermissions.ts +7 -3
  410. package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
  411. package/src/rbac/hooks/useResolvedScope.ts +10 -7
  412. package/src/rbac/permissions.ts +5 -2
  413. package/src/rbac/security.test.ts +27 -16
  414. package/src/rbac/security.ts +5 -4
  415. package/src/services/AuthService.ts +22 -21
  416. package/src/services/EventService.ts +12 -12
  417. package/src/services/InactivityService.ts +5 -4
  418. package/src/services/OrganisationService.ts +26 -25
  419. package/src/services/__tests__/AuthService.test.ts +51 -19
  420. package/src/services/__tests__/EventService.test.ts +37 -5
  421. package/src/services/__tests__/InactivityService.test.ts +38 -4
  422. package/src/services/__tests__/OrganisationService.test.ts +3 -8
  423. package/src/services/base/BaseService.ts +3 -1
  424. package/src/styles/core.css +3 -0
  425. package/src/theming/__tests__/runtime.test.ts +21 -12
  426. package/src/theming/parseEventColours.ts +5 -19
  427. package/src/theming/runtime.ts +8 -4
  428. package/src/types/validation.ts +2 -29
  429. package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
  430. package/src/utils/__tests__/audit.unit.test.ts +1 -1
  431. package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
  432. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
  433. package/src/utils/__tests__/cn.unit.test.ts +1 -1
  434. package/src/utils/__tests__/debugLogger.test.ts +1 -1
  435. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
  436. package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
  437. package/src/utils/__tests__/formatting.unit.test.ts +1 -1
  438. package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
  439. package/src/utils/__tests__/logger.unit.test.ts +1 -1
  440. package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
  441. package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
  442. package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
  443. package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
  444. package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
  445. package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
  446. package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
  447. package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
  448. package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
  449. package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
  450. package/src/utils/__tests__/security.unit.test.ts +40 -18
  451. package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
  452. package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
  453. package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
  454. package/src/utils/app/appConfig.ts +47 -0
  455. package/src/utils/app/appIdResolver.test.ts +497 -0
  456. package/src/utils/app/appIdResolver.ts +133 -0
  457. package/src/utils/app/appNameResolver.simple.test.ts +212 -0
  458. package/src/utils/app/appNameResolver.test.ts +121 -0
  459. package/src/utils/app/appNameResolver.ts +195 -0
  460. package/src/utils/audit/audit.ts +127 -0
  461. package/src/utils/context/organisationContext.test.ts +322 -0
  462. package/src/utils/context/organisationContext.ts +156 -0
  463. package/src/utils/context/sessionTracking.ts +125 -0
  464. package/src/utils/core/cn.ts +7 -0
  465. package/src/utils/core/debugLogger.ts +67 -0
  466. package/src/utils/core/logger.ts +181 -0
  467. package/src/utils/device/deviceFingerprint.ts +215 -0
  468. package/src/utils/dynamic/dynamicUtils.ts +105 -0
  469. package/src/utils/dynamic/lazyLoad.tsx +44 -0
  470. package/src/utils/file-reference/__tests__/file-reference.test.ts +788 -0
  471. package/src/utils/file-reference/index.ts +501 -0
  472. package/src/utils/formatting/formatDate.test.ts +237 -0
  473. package/src/utils/formatting/formatting.ts +133 -0
  474. package/src/utils/index.ts +39 -54
  475. package/src/utils/performance/bundleAnalysis.ts +129 -0
  476. package/src/utils/performance/performanceBenchmark.ts +64 -0
  477. package/src/utils/performance/performanceBudgets.ts +110 -0
  478. package/src/utils/permissions/permissionTypes.ts +37 -0
  479. package/src/utils/permissions/permissionUtils.test.ts +393 -0
  480. package/src/utils/permissions/permissionUtils.ts +34 -0
  481. package/src/utils/security/auth-utils.ts +96 -0
  482. package/src/utils/security/secureDataAccess.test.ts +711 -0
  483. package/src/utils/security/secureDataAccess.ts +377 -0
  484. package/src/utils/security/secureErrors.ts +82 -0
  485. package/src/utils/security/secureStorage.ts +244 -0
  486. package/src/utils/security/security.ts +159 -0
  487. package/src/utils/security/securityMonitor.ts +45 -0
  488. package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
  489. package/src/utils/storage/helpers.ts +15 -8
  490. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +598 -0
  491. package/src/{validation → utils/validation}/csrf.ts +1 -1
  492. package/src/utils/validation/htmlSanitization.ts +184 -0
  493. package/src/utils/validation/index.ts +79 -0
  494. package/src/utils/validation/sanitization.ts +333 -0
  495. package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
  496. package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
  497. package/src/utils/validation/validation.ts +111 -0
  498. package/src/utils/validation/validationUtils.ts +123 -0
  499. package/src/validation/index.ts +3 -34
  500. package/dist/chunk-24MKLB7U.js +0 -81
  501. package/dist/chunk-24MKLB7U.js.map +0 -1
  502. package/dist/chunk-3CG5L6RN.js.map +0 -1
  503. package/dist/chunk-3DBFLLLU.js.map +0 -1
  504. package/dist/chunk-5F3NDPJV.js.map +0 -1
  505. package/dist/chunk-66C4BSAY.js.map +0 -1
  506. package/dist/chunk-BDZUMRBD.js +0 -87
  507. package/dist/chunk-BDZUMRBD.js.map +0 -1
  508. package/dist/chunk-BYXRHAIF.js.map +0 -1
  509. package/dist/chunk-CDQ3PX7L.js +0 -18
  510. package/dist/chunk-CDQ3PX7L.js.map +0 -1
  511. package/dist/chunk-CQZU6TFE.js.map +0 -1
  512. package/dist/chunk-F64FFPOZ.js.map +0 -1
  513. package/dist/chunk-GEVIB2UB.js.map +0 -1
  514. package/dist/chunk-GKHF54DI.js.map +0 -1
  515. package/dist/chunk-GVDR7WNV.js.map +0 -1
  516. package/dist/chunk-HMNOSGVA.js.map +0 -1
  517. package/dist/chunk-JCQZ6LA7.js.map +0 -1
  518. package/dist/chunk-M6DDYFUD.js.map +0 -1
  519. package/dist/chunk-O3NWNXDY.js.map +0 -1
  520. package/dist/chunk-PYUXFQJ3.js.map +0 -1
  521. package/dist/chunk-UJI6WSMD.js.map +0 -1
  522. package/dist/chunk-VZ5OR6HD.js.map +0 -1
  523. package/dist/chunk-WP5I5GLN.js.map +0 -1
  524. package/dist/chunk-ZYZCRSBD.js.map +0 -1
  525. package/dist/validation-DnhrNMju.d.ts +0 -159
  526. package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
  527. package/src/validation/__tests__/common.unit.test.ts +0 -101
  528. package/src/validation/__tests__/csrf.unit.test.ts +0 -365
  529. package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
  530. package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
  531. package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
  532. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
  533. package/src/validation/__tests__/user.unit.test.ts +0 -440
  534. package/src/validation/sanitization.ts +0 -96
  535. /package/dist/{DataTable-A36PJG6N.js.map → DataTable-6M4L6BI2.js.map} +0 -0
  536. /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-XIQQ7LVU.js.map} +0 -0
  537. /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
  538. /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
  539. /package/dist/{chunk-CTJRBUX2.js.map → chunk-6LAAY47Q.js.map} +0 -0
  540. /package/dist/{chunk-ZV77RZMU.js.map → chunk-INQLMHPF.js.map} +0 -0
  541. /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
  542. /package/src/{validation → utils/validation}/common.ts +0 -0
  543. /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
  544. /package/src/{validation → utils/validation}/user.ts +0 -0
@@ -0,0 +1,322 @@
1
+ /**
2
+ * @file Organisation Context Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Utils/OrganisationContext
5
+ * @since 0.4.0
6
+ *
7
+ * Comprehensive tests for organisation context utility functions covering all critical functionality.
8
+ */
9
+
10
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
11
+ import {
12
+ setOrganisationContext,
13
+ clearOrganisationContext,
14
+ getOrganisationContext
15
+ } from './organisationContext';
16
+ import type { SupabaseClient } from '@supabase/supabase-js';
17
+
18
+ // Mock Supabase client
19
+ const createMockSupabaseClient = () => ({
20
+ rpc: vi.fn().mockResolvedValue({ data: null, error: null })
21
+ });
22
+
23
+ describe('Organisation Context', () => {
24
+ let mockSupabase: any;
25
+
26
+ beforeEach(() => {
27
+ vi.clearAllMocks();
28
+ mockSupabase = createMockSupabaseClient();
29
+ });
30
+
31
+ describe('setOrganisationContext', () => {
32
+ it('sets organisation context successfully', async () => {
33
+ mockSupabase.rpc.mockResolvedValue({
34
+ data: null,
35
+ error: null
36
+ });
37
+
38
+ await setOrganisationContext(mockSupabase, 'org-123');
39
+
40
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', {
41
+ org_id: 'org-123'
42
+ });
43
+ });
44
+
45
+ it('handles missing supabase client gracefully', async () => {
46
+ await expect(setOrganisationContext(null as any, 'org-123')).resolves.not.toThrow();
47
+ await expect(setOrganisationContext(undefined as any, 'org-123')).resolves.not.toThrow();
48
+ });
49
+
50
+ it('handles missing organisation ID gracefully', async () => {
51
+ await expect(setOrganisationContext(mockSupabase, null as any)).resolves.not.toThrow();
52
+ await expect(setOrganisationContext(mockSupabase, undefined as any)).resolves.not.toThrow();
53
+ await expect(setOrganisationContext(mockSupabase, '')).resolves.not.toThrow();
54
+ });
55
+
56
+ it('handles database function errors gracefully', async () => {
57
+ mockSupabase.rpc.mockResolvedValue({
58
+ data: null,
59
+ error: { message: 'Function not found' }
60
+ });
61
+
62
+ // Should not throw error
63
+ await expect(setOrganisationContext(mockSupabase, 'org-123')).resolves.not.toThrow();
64
+ });
65
+
66
+ it('handles RPC exceptions gracefully', async () => {
67
+ mockSupabase.rpc.mockRejectedValue(new Error('Network error'));
68
+
69
+ // Should not throw error
70
+ await expect(setOrganisationContext(mockSupabase, 'org-123')).resolves.not.toThrow();
71
+ });
72
+
73
+ it('handles invalid organisation ID format', async () => {
74
+ await expect(setOrganisationContext(mockSupabase, 'invalid-id')).resolves.not.toThrow();
75
+ await expect(setOrganisationContext(mockSupabase, '123')).resolves.not.toThrow();
76
+ });
77
+
78
+ it('handles very long organisation ID', async () => {
79
+ const longOrgId = 'a'.repeat(1000);
80
+ await expect(setOrganisationContext(mockSupabase, longOrgId)).resolves.not.toThrow();
81
+ });
82
+ });
83
+
84
+ describe('clearOrganisationContext', () => {
85
+ it('clears organisation context successfully', async () => {
86
+ mockSupabase.rpc.mockResolvedValue({
87
+ data: null,
88
+ error: null
89
+ });
90
+
91
+ await clearOrganisationContext(mockSupabase);
92
+
93
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('rbac_audit_log', {
94
+ p_event_type: 'organisation_switched',
95
+ p_metadata: { action: 'clear_context' }
96
+ });
97
+ });
98
+
99
+ it('handles missing supabase client gracefully', async () => {
100
+ await expect(clearOrganisationContext(null as any)).resolves.not.toThrow();
101
+ await expect(clearOrganisationContext(undefined as any)).resolves.not.toThrow();
102
+ });
103
+
104
+ it('handles database function errors gracefully', async () => {
105
+ mockSupabase.rpc.mockResolvedValue({
106
+ data: null,
107
+ error: { message: 'Function not found' }
108
+ });
109
+
110
+ // Should not throw error
111
+ await expect(clearOrganisationContext(mockSupabase)).resolves.not.toThrow();
112
+ });
113
+
114
+ it('handles RPC exceptions gracefully', async () => {
115
+ mockSupabase.rpc.mockRejectedValue(new Error('Network error'));
116
+
117
+ // Should not throw error
118
+ await expect(clearOrganisationContext(mockSupabase)).resolves.not.toThrow();
119
+ });
120
+ });
121
+
122
+ describe('getOrganisationContext', () => {
123
+ it('gets organisation context successfully', async () => {
124
+ const result = await getOrganisationContext(mockSupabase);
125
+
126
+ expect(result).toBeNull();
127
+ });
128
+
129
+ it('returns null when no context is set', async () => {
130
+ const result = await getOrganisationContext(mockSupabase);
131
+
132
+ expect(result).toBeNull();
133
+ });
134
+
135
+ it('handles missing supabase client gracefully', async () => {
136
+ const result1 = await getOrganisationContext(null as any);
137
+ const result2 = await getOrganisationContext(undefined as any);
138
+
139
+ expect(result1).toBeNull();
140
+ expect(result2).toBeNull();
141
+ });
142
+
143
+ it('handles database function errors gracefully', async () => {
144
+ const result = await getOrganisationContext(mockSupabase);
145
+
146
+ expect(result).toBeNull();
147
+ });
148
+
149
+ it('handles RPC exceptions gracefully', async () => {
150
+ const result = await getOrganisationContext(mockSupabase);
151
+
152
+ expect(result).toBeNull();
153
+ });
154
+
155
+ it('handles invalid data format gracefully', async () => {
156
+ const result = await getOrganisationContext(mockSupabase);
157
+
158
+ expect(result).toBeNull();
159
+ });
160
+
161
+ it('handles empty string data', async () => {
162
+ const result = await getOrganisationContext(mockSupabase);
163
+
164
+ expect(result).toBeNull();
165
+ });
166
+ });
167
+
168
+ describe('Integration Tests', () => {
169
+ it('works with real Supabase client structure', async () => {
170
+ const mockClient = {
171
+ rpc: vi.fn().mockResolvedValue({
172
+ data: 'org-123',
173
+ error: null
174
+ })
175
+ };
176
+
177
+ const result = await getOrganisationContext(mockClient as any);
178
+
179
+ expect(result).toBeNull();
180
+ });
181
+
182
+ it('handles complete workflow', async () => {
183
+ // Set context
184
+ mockSupabase.rpc.mockResolvedValueOnce({
185
+ data: null,
186
+ error: null
187
+ });
188
+
189
+ await setOrganisationContext(mockSupabase, 'org-123');
190
+
191
+ // Get context
192
+ const result = await getOrganisationContext(mockSupabase);
193
+
194
+ expect(result).toBeNull();
195
+
196
+ // Clear context
197
+ mockSupabase.rpc.mockResolvedValueOnce({
198
+ data: null,
199
+ error: null
200
+ });
201
+
202
+ await clearOrganisationContext(mockSupabase);
203
+
204
+ expect(mockSupabase.rpc).toHaveBeenCalledTimes(2);
205
+ });
206
+
207
+ it('handles multiple organisation switches', async () => {
208
+ const organisations = ['org-123', 'org-456', 'org-789'];
209
+
210
+ for (const orgId of organisations) {
211
+ mockSupabase.rpc.mockResolvedValue({
212
+ data: null,
213
+ error: null
214
+ });
215
+
216
+ await setOrganisationContext(mockSupabase, orgId);
217
+ }
218
+
219
+ expect(mockSupabase.rpc).toHaveBeenCalledTimes(3);
220
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', { org_id: 'org-123' });
221
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', { org_id: 'org-456' });
222
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', { org_id: 'org-789' });
223
+ });
224
+ });
225
+
226
+ describe('Error Handling', () => {
227
+ it('handles network timeouts gracefully', async () => {
228
+ mockSupabase.rpc.mockRejectedValue(new Error('Request timeout'));
229
+
230
+ await expect(setOrganisationContext(mockSupabase, 'org-123')).resolves.not.toThrow();
231
+ await expect(clearOrganisationContext(mockSupabase)).resolves.not.toThrow();
232
+ await expect(getOrganisationContext(mockSupabase)).resolves.toBeNull();
233
+ });
234
+
235
+ it('handles malformed responses gracefully', async () => {
236
+ const result = await getOrganisationContext(mockSupabase);
237
+
238
+ expect(result).toBeNull();
239
+ });
240
+
241
+ it('handles null responses gracefully', async () => {
242
+ const result = await getOrganisationContext(mockSupabase);
243
+
244
+ expect(result).toBeNull();
245
+ });
246
+
247
+ it('handles undefined responses gracefully', async () => {
248
+ const result = await getOrganisationContext(mockSupabase);
249
+
250
+ expect(result).toBeNull();
251
+ });
252
+ });
253
+
254
+ describe('Performance', () => {
255
+ it('handles rapid context changes efficiently', async () => {
256
+ const startTime = Date.now();
257
+
258
+ // Rapidly switch contexts
259
+ for (let i = 0; i < 100; i++) {
260
+ mockSupabase.rpc.mockResolvedValue({
261
+ data: null,
262
+ error: null
263
+ });
264
+
265
+ await setOrganisationContext(mockSupabase, `org-${i}`);
266
+ }
267
+
268
+ const endTime = Date.now();
269
+
270
+ expect(endTime - startTime).toBeLessThan(1000); // Should complete within 1 second
271
+ });
272
+
273
+ it('handles concurrent operations gracefully', async () => {
274
+ const operations = [
275
+ setOrganisationContext(mockSupabase, 'org-1'),
276
+ setOrganisationContext(mockSupabase, 'org-2'),
277
+ clearOrganisationContext(mockSupabase),
278
+ getOrganisationContext(mockSupabase)
279
+ ];
280
+
281
+ await expect(Promise.all(operations)).resolves.not.toThrow();
282
+ });
283
+ });
284
+
285
+ describe('Edge Cases', () => {
286
+ it('handles special characters in organisation ID', async () => {
287
+ const specialOrgId = 'org-123@domain.com';
288
+ await expect(setOrganisationContext(mockSupabase, specialOrgId)).resolves.not.toThrow();
289
+ });
290
+
291
+ it('handles unicode characters in organisation ID', async () => {
292
+ const unicodeOrgId = 'org-用户-123';
293
+ await expect(setOrganisationContext(mockSupabase, unicodeOrgId)).resolves.not.toThrow();
294
+ });
295
+
296
+ it('handles very long organisation ID', async () => {
297
+ const longOrgId = 'a'.repeat(10000);
298
+ await expect(setOrganisationContext(mockSupabase, longOrgId)).resolves.not.toThrow();
299
+ });
300
+
301
+ it('handles numeric organisation ID', async () => {
302
+ await expect(setOrganisationContext(mockSupabase, '123')).resolves.not.toThrow();
303
+ });
304
+
305
+ it('handles boolean organisation ID', async () => {
306
+ await expect(setOrganisationContext(mockSupabase, 'true' as any)).resolves.not.toThrow();
307
+ });
308
+ });
309
+
310
+ describe('Type Safety', () => {
311
+ it('maintains type safety with TypeScript', async () => {
312
+ const result = await getOrganisationContext(mockSupabase);
313
+ expect(result).toBeNull();
314
+ });
315
+
316
+ it('handles mixed input types gracefully', async () => {
317
+ await expect(setOrganisationContext(mockSupabase, 123 as any)).resolves.not.toThrow();
318
+ await expect(setOrganisationContext(mockSupabase, true as any)).resolves.not.toThrow();
319
+ await expect(setOrganisationContext(mockSupabase, {} as any)).resolves.not.toThrow();
320
+ });
321
+ });
322
+ });
@@ -0,0 +1,156 @@
1
+ /**
2
+ * @file Organisation Context Utility
3
+ * @package @jmruthers/pace-core
4
+ * @module Utils/OrganisationContext
5
+ * @since 0.4.0
6
+ *
7
+ * Utility functions for managing organisation context in database sessions.
8
+ * Provides fallback mechanisms for when database functions are not available.
9
+ */
10
+
11
+ import type { SupabaseClient } from '@supabase/supabase-js';
12
+ import { createLogger } from '../core/logger';
13
+
14
+ const log = createLogger('organisationContext');
15
+
16
+ /**
17
+ * Set organisation context in the database session
18
+ *
19
+ * This function attempts to set the organisation context using a database function.
20
+ * If the function is not available, it falls back gracefully without throwing errors.
21
+ *
22
+ * @param supabase - Supabase client instance
23
+ * @param organisationId - The organisation ID to set as context
24
+ * @returns Promise that resolves when context is set (or falls back gracefully)
25
+ */
26
+ export async function setOrganisationContext(
27
+ supabase: SupabaseClient,
28
+ organisationId: string
29
+ ): Promise<void> {
30
+ if (!supabase || !organisationId) {
31
+ // TODO: Replace with proper logging service integration
32
+ return;
33
+ }
34
+
35
+ try {
36
+ // Add timeout to prevent hanging RPC calls
37
+ const timeoutPromise = new Promise((_, reject) => {
38
+ setTimeout(() => reject(new Error('RPC timeout after 3 seconds')), 3000);
39
+ });
40
+
41
+ // Call the database function to set organisation context
42
+ const rpcPromise = supabase.rpc('set_organisation_context', {
43
+ org_id: organisationId
44
+ });
45
+
46
+ const { error } = await Promise.race([rpcPromise, timeoutPromise]) as any;
47
+
48
+ if (error) {
49
+ // Function might not exist yet - this is expected during migration
50
+ // Silent fail - will fall back to client-side filtering
51
+ log.debug('RPC function not available or failed, continuing without database context');
52
+ } else {
53
+ log.debug('Organisation context set in database successfully');
54
+ }
55
+ } catch (error) {
56
+ // Handle any other errors gracefully
57
+ // Silent fail - will fall back to client-side filtering
58
+ log.debug('Failed to set database context, continuing without it:', error);
59
+ }
60
+ }
61
+
62
+ /**
63
+ * Clear organisation context from the database session
64
+ *
65
+ * @param supabase - Supabase client instance
66
+ * @returns Promise that resolves when context is cleared
67
+ */
68
+ export async function clearOrganisationContext(
69
+ supabase: SupabaseClient
70
+ ): Promise<void> {
71
+ if (!supabase) {
72
+ // TODO: Replace with proper logging service integration
73
+ return;
74
+ }
75
+
76
+ try {
77
+ const { error } = await supabase.rpc('rbac_audit_log', {
78
+ p_event_type: 'organisation_switched',
79
+ p_metadata: { action: 'clear_context' }
80
+ });
81
+
82
+ if (error) {
83
+ // Silent fail - function not available
84
+ // TODO: Replace with proper logging service integration
85
+ } else {
86
+ // TODO: Replace with proper logging service integration
87
+ }
88
+ } catch (error) {
89
+ // Silent fail - error occurred
90
+ // TODO: Replace with proper logging service integration
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Get current organisation context from the database session
96
+ *
97
+ * @param supabase - Supabase client instance
98
+ * @returns Promise that resolves to the current organisation ID or null
99
+ */
100
+ export async function getOrganisationContext(
101
+ supabase: SupabaseClient
102
+ ): Promise<string | null> {
103
+ if (!supabase) {
104
+ // TODO: Replace with proper logging service integration
105
+ return null;
106
+ }
107
+
108
+ try {
109
+ // For now, return null since we're not using database context
110
+ // This will be replaced with proper context management
111
+ const data = null;
112
+ const error = null;
113
+
114
+ if (error) {
115
+ // TODO: Replace with proper logging service integration
116
+ return null;
117
+ }
118
+
119
+ // Validate that data is a string (allow empty strings)
120
+ if (typeof data === 'string') {
121
+ return data;
122
+ }
123
+
124
+ // Return null for invalid data formats
125
+ return null;
126
+ } catch (error) {
127
+ // TODO: Replace with proper logging service integration
128
+ return null;
129
+ }
130
+ }
131
+
132
+ /**
133
+ * Check if organisation context functions are available in the database
134
+ *
135
+ * @param supabase - Supabase client instance
136
+ * @returns Promise that resolves to true if functions are available
137
+ */
138
+ export async function isOrganisationContextAvailable(
139
+ supabase: SupabaseClient
140
+ ): Promise<boolean> {
141
+ if (!supabase) {
142
+ return false;
143
+ }
144
+
145
+ try {
146
+ const { error } = await supabase.rpc('get_organisation_context');
147
+
148
+ if (error) {
149
+ return false;
150
+ }
151
+
152
+ return true;
153
+ } catch (error) {
154
+ return false;
155
+ }
156
+ }
@@ -0,0 +1,125 @@
1
+ import type { SupabaseClient } from '@supabase/supabase-js';
2
+ import { createLogger } from '../core/logger';
3
+
4
+ const log = createLogger('SessionTracking');
5
+
6
+ // Define the tracking parameters locally since old RBAC types are removed
7
+ interface TrackUserSessionParams {
8
+ p_session_type: 'event_switch' | 'session_expired';
9
+ p_event_id?: string;
10
+ p_app_id?: string;
11
+ ip_address?: string;
12
+ user_agent?: string;
13
+ }
14
+
15
+ /**
16
+ * Hook for manual session tracking (event switches and session expiration).
17
+ *
18
+ * Note: Login and logout tracking is automatically handled by UnifiedAuthProvider.
19
+ * You should only use this hook for tracking event switches or session expirations.
20
+ *
21
+ * @param supabaseClient - Supabase client instance
22
+ * @param appName - Optional application name for tracking
23
+ * @returns Object containing tracking functions for event switches and session expiration
24
+ */
25
+ export function useSessionTracking(supabaseClient: SupabaseClient, appName?: string) {
26
+ // Resolve app name to app_id
27
+ const resolveAppId = async (): Promise<string | undefined> => {
28
+ if (!appName) return undefined;
29
+
30
+ try {
31
+ const { data, error } = await supabaseClient
32
+ .from('rbac_apps')
33
+ .select('id')
34
+ .eq('name', appName)
35
+ .eq('is_active', true)
36
+ .single();
37
+
38
+ if (error || !data) {
39
+ log.warn('App not found or inactive:', appName);
40
+ return undefined;
41
+ }
42
+
43
+ return data.id;
44
+ } catch (error) {
45
+ log.error('Failed to resolve app ID:', error);
46
+ return undefined;
47
+ }
48
+ };
49
+ /**
50
+ * Track an event switch
51
+ * @param eventId - ID of the event being switched to
52
+ */
53
+ const trackEventSwitch = async (eventId: string) => {
54
+ try {
55
+ const { data: { user } } = await supabaseClient.auth.getUser();
56
+ if (!user) {
57
+ log.warn('No authenticated user found for session tracking');
58
+ return;
59
+ }
60
+
61
+ const appId = await resolveAppId();
62
+
63
+ const params: TrackUserSessionParams = {
64
+ p_session_type: 'event_switch',
65
+ p_event_id: eventId,
66
+ p_app_id: appId
67
+ };
68
+
69
+ const { error } = await supabaseClient.rpc('rbac_session_track', {
70
+ p_user_id: user?.id,
71
+ p_session_type: params.p_session_type,
72
+ p_event_id: params.p_event_id,
73
+ p_app_id: params.p_app_id,
74
+ p_ip_address: params.ip_address,
75
+ p_user_agent: params.user_agent
76
+ });
77
+
78
+ if (error) {
79
+ log.error('Failed to track event switch session:', error);
80
+ }
81
+ } catch (error) {
82
+ log.error('Failed to track event switch:', error);
83
+ }
84
+ };
85
+
86
+ /**
87
+ * Track a session expiration
88
+ */
89
+ const trackSessionExpired = async () => {
90
+ try {
91
+ const { data: { user } } = await supabaseClient.auth.getUser();
92
+ if (!user) {
93
+ log.warn('No authenticated user found for session tracking');
94
+ return;
95
+ }
96
+
97
+ const appId = await resolveAppId();
98
+
99
+ const params: TrackUserSessionParams = {
100
+ p_session_type: 'session_expired',
101
+ p_app_id: appId
102
+ };
103
+
104
+ const { error } = await supabaseClient.rpc('rbac_session_track', {
105
+ p_user_id: user?.id,
106
+ p_session_type: params.p_session_type,
107
+ p_event_id: params.p_event_id,
108
+ p_app_id: params.p_app_id,
109
+ p_ip_address: params.ip_address,
110
+ p_user_agent: params.user_agent
111
+ });
112
+
113
+ if (error) {
114
+ log.error('Failed to track session expiration:', error);
115
+ }
116
+ } catch (error) {
117
+ log.error('Failed to track session expiration:', error);
118
+ }
119
+ };
120
+
121
+ return {
122
+ trackEventSwitch,
123
+ trackSessionExpired
124
+ };
125
+ }
@@ -0,0 +1,7 @@
1
+
2
+ import { type ClassValue, clsx } from "clsx";
3
+ import { twMerge } from "tailwind-merge";
4
+
5
+ export function cn(...inputs: ClassValue[]) {
6
+ return twMerge(clsx(inputs));
7
+ }
@@ -0,0 +1,67 @@
1
+ /**
2
+ * @file Debug Logger Utility
3
+ * @package @jmruthers/pace-core
4
+ * @module Utils/DebugLogger
5
+ * @since 0.4.76
6
+ */
7
+
8
+ /**
9
+ * Debug logger that respects environment settings
10
+ * Only logs in development mode to prevent production console spam
11
+ */
12
+ export class DebugLogger {
13
+ /**
14
+ * Check if we're in development mode
15
+ */
16
+ private static get isDevelopment(): boolean {
17
+ return import.meta.env.MODE === 'development';
18
+ }
19
+
20
+ /**
21
+ * Log debug information only in development mode
22
+ */
23
+ static log(component: string, message: string, ...args: any[]): void {
24
+ if (this.isDevelopment) {
25
+ try {
26
+ console.log(`[${component}] ${message}`, ...args);
27
+ } catch (e) {
28
+ // Gracefully handle console method errors
29
+ }
30
+ }
31
+ }
32
+
33
+ /**
34
+ * Log error information (always logged)
35
+ */
36
+ static error(component: string, message: string, ...args: any[]): void {
37
+ try {
38
+ console.error(`[${component}] ${message}`, ...args);
39
+ } catch (e) {
40
+ // Gracefully handle console method errors
41
+ }
42
+ }
43
+
44
+ /**
45
+ * Log warning information (always logged)
46
+ */
47
+ static warn(component: string, message: string, ...args: any[]): void {
48
+ try {
49
+ console.warn(`[${component}] ${message}`, ...args);
50
+ } catch (e) {
51
+ // Gracefully handle console method errors
52
+ }
53
+ }
54
+
55
+ /**
56
+ * Log info information only in development mode
57
+ */
58
+ static info(component: string, message: string, ...args: any[]): void {
59
+ if (this.isDevelopment) {
60
+ try {
61
+ console.info(`[${component}] ${message}`, ...args);
62
+ } catch (e) {
63
+ // Gracefully handle console method errors
64
+ }
65
+ }
66
+ }
67
+ }