@jmruthers/pace-core 0.5.135 → 0.5.136

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 (522) hide show
  1. package/dist/{DataTable-C7GaRZye.d.ts → DataTable-CWAZZcXC.d.ts} +1 -1
  2. package/dist/{DataTable-A36PJG6N.js → DataTable-CYOHOX3O.js} +25 -13
  3. package/dist/{PublicLoadingSpinner-CUAnTvcg.d.ts → EventLogo-801uofbR.d.ts} +51 -135
  4. package/dist/UnifiedAuthProvider-5E5TUNMS.js +17 -0
  5. package/dist/{UnifiedAuthProvider-BVKmQd9u.d.ts → UnifiedAuthProvider-DJxGTftH.d.ts} +1 -1
  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-CTJRBUX2.js → chunk-2TWNJ46Y.js} +2 -2
  9. package/dist/{chunk-UJI6WSMD.js → chunk-444EZN6N.js} +3 -3
  10. package/dist/chunk-444EZN6N.js.map +1 -0
  11. package/dist/{chunk-3CG5L6RN.js → chunk-4MT5BGGL.js} +90 -73
  12. package/dist/chunk-4MT5BGGL.js.map +1 -0
  13. package/dist/{chunk-PYUXFQJ3.js → chunk-56XJ3TU6.js} +2 -2
  14. package/dist/chunk-56XJ3TU6.js.map +1 -0
  15. package/dist/chunk-5DPZ5EAT.js +60 -0
  16. package/dist/chunk-5DPZ5EAT.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-APIBCTL2.js +670 -0
  20. package/dist/chunk-APIBCTL2.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-WP5I5GLN.js → chunk-BVYWGZVV.js} +112 -97
  24. package/dist/chunk-BVYWGZVV.js.map +1 -0
  25. package/dist/{chunk-GEVIB2UB.js → chunk-ERISIBYU.js} +14 -5
  26. package/dist/chunk-ERISIBYU.js.map +1 -0
  27. package/dist/{chunk-CQZU6TFE.js → chunk-FHWWBIHA.js} +100 -62
  28. package/dist/chunk-FHWWBIHA.js.map +1 -0
  29. package/dist/{chunk-O3NWNXDY.js → chunk-FMUCXFII.js} +2 -2
  30. package/dist/chunk-FMUCXFII.js.map +1 -0
  31. package/dist/{chunk-GVDR7WNV.js → chunk-HJGGOMQ6.js} +194 -518
  32. package/dist/chunk-HJGGOMQ6.js.map +1 -0
  33. package/dist/{chunk-BDZUMRBD.js → chunk-K2WWTH7O.js} +13 -6
  34. package/dist/chunk-K2WWTH7O.js.map +1 -0
  35. package/dist/{chunk-BYXRHAIF.js → chunk-L6PGMCMD.js} +23 -14
  36. package/dist/chunk-L6PGMCMD.js.map +1 -0
  37. package/dist/chunk-LMC26NLJ.js +84 -0
  38. package/dist/chunk-LMC26NLJ.js.map +1 -0
  39. package/dist/{chunk-M6DDYFUD.js → chunk-LS353YLY.js} +19 -16
  40. package/dist/chunk-LS353YLY.js.map +1 -0
  41. package/dist/{chunk-ZYZCRSBD.js → chunk-LTV3XIJJ.js} +16 -11
  42. package/dist/chunk-LTV3XIJJ.js.map +1 -0
  43. package/dist/{chunk-HMNOSGVA.js → chunk-NOHEVYVX.js} +377 -666
  44. package/dist/chunk-NOHEVYVX.js.map +1 -0
  45. package/dist/{chunk-JCQZ6LA7.js → chunk-Q5QRDWKI.js} +9 -3
  46. package/dist/chunk-Q5QRDWKI.js.map +1 -0
  47. package/dist/chunk-S5OFRT4M.js +94 -0
  48. package/dist/chunk-S5OFRT4M.js.map +1 -0
  49. package/dist/{chunk-3DBFLLLU.js → chunk-SBVILCCA.js} +14 -9
  50. package/dist/chunk-SBVILCCA.js.map +1 -0
  51. package/dist/{chunk-TGIY2AR2.js → chunk-SL2YQDR6.js} +4 -3
  52. package/dist/{chunk-TGIY2AR2.js.map → chunk-SL2YQDR6.js.map} +1 -1
  53. package/dist/{chunk-VZ5OR6HD.js → chunk-TVYPTYOY.js} +55 -179
  54. package/dist/chunk-TVYPTYOY.js.map +1 -0
  55. package/dist/{chunk-ZV77RZMU.js → chunk-XARJS7CD.js} +2 -2
  56. package/dist/chunk-XDNLUEXI.js +138 -0
  57. package/dist/chunk-XDNLUEXI.js.map +1 -0
  58. package/dist/{chunk-F64FFPOZ.js → chunk-YLKIDTUK.js} +26 -20
  59. package/dist/chunk-YLKIDTUK.js.map +1 -0
  60. package/dist/{chunk-5F3NDPJV.js → chunk-ZZ2SS7NI.js} +10 -5
  61. package/dist/chunk-ZZ2SS7NI.js.map +1 -0
  62. package/dist/components.d.ts +7 -287
  63. package/dist/components.js +26 -157
  64. package/dist/components.js.map +1 -1
  65. package/dist/{file-reference-C9isKNPn.d.ts → file-reference-C6Gkn77H.d.ts} +1 -1
  66. package/dist/{formatting-DFcCxUEk.d.ts → formatting-CvUXy2mF.d.ts} +1 -1
  67. package/dist/hooks.d.ts +3 -3
  68. package/dist/hooks.js +22 -16
  69. package/dist/hooks.js.map +1 -1
  70. package/dist/index.d.ts +101 -9
  71. package/dist/index.js +43 -31
  72. package/dist/index.js.map +1 -1
  73. package/dist/providers.d.ts +1 -1
  74. package/dist/providers.js +5 -4
  75. package/dist/rbac/index.js +13 -12
  76. package/dist/styles/index.js +2 -1
  77. package/dist/theming/runtime.d.ts +2 -19
  78. package/dist/theming/runtime.js +2 -1
  79. package/dist/{types-D5rqZQXk.d.ts → types-Dfz9dmVH.d.ts} +12 -1
  80. package/dist/types.d.ts +2 -2
  81. package/dist/types.js +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 +195 -232
  85. package/dist/utils.js +173 -331
  86. package/dist/utils.js.map +1 -1
  87. package/dist/{validation-DnhrNMju.d.ts → validation-8npbysjg.d.ts} +26 -8
  88. package/dist/validation.d.ts +261 -10
  89. package/dist/validation.js +82 -440
  90. package/dist/validation.js.map +1 -1
  91. package/docs/api/classes/ColumnFactory.md +1 -1
  92. package/docs/api/classes/ErrorBoundary.md +6 -6
  93. package/docs/api/classes/InvalidScopeError.md +1 -1
  94. package/docs/api/classes/MissingUserContextError.md +1 -1
  95. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  96. package/docs/api/classes/PermissionDeniedError.md +1 -1
  97. package/docs/api/classes/PublicErrorBoundary.md +1 -1
  98. package/docs/api/classes/RBACAuditManager.md +6 -6
  99. package/docs/api/classes/RBACCache.md +1 -1
  100. package/docs/api/classes/RBACEngine.md +7 -7
  101. package/docs/api/classes/RBACError.md +1 -1
  102. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  103. package/docs/api/classes/SecureSupabaseClient.md +1 -1
  104. package/docs/api/classes/StorageUtils.md +1 -1
  105. package/docs/api/enums/FileCategory.md +1 -1
  106. package/docs/api/interfaces/AggregateConfig.md +4 -4
  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 +514 -212
  199. package/docs/api-reference/components.md +106 -26
  200. package/docs/architecture/README.md +0 -2
  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/examples/README.md +30 -14
  205. package/examples/STRUCTURE.md +125 -0
  206. package/examples/components/DataTable/HierarchicalActionsExample.tsx +421 -0
  207. package/examples/components/DataTable/HierarchicalExample.tsx +475 -0
  208. package/examples/components/DataTable/InitialPageSizeExample.tsx +177 -0
  209. package/examples/components/DataTable/PerformanceExample.tsx +506 -0
  210. package/examples/components/DataTable/index.ts +13 -0
  211. package/examples/components/Dialog/BasicHtmlTest.tsx +55 -0
  212. package/examples/components/Dialog/DebugHtmlExample.tsx +68 -0
  213. package/examples/components/Dialog/HtmlDialogExample.tsx +202 -0
  214. package/examples/components/Dialog/ScrollableDialogExample.tsx +290 -0
  215. package/examples/components/Dialog/SimpleHtmlTest.tsx +61 -0
  216. package/examples/components/Dialog/SmartDialogExample.tsx +322 -0
  217. package/examples/components/Dialog/index.ts +15 -0
  218. package/examples/components/index.ts +11 -0
  219. package/examples/features/index.ts +12 -0
  220. package/examples/{public-pages → features/public-pages}/CorrectPublicPageImplementation.tsx +1 -1
  221. package/examples/{public-pages → features/public-pages}/PublicEventPage.tsx +1 -1
  222. package/examples/{public-pages → features/public-pages}/PublicPageApp.tsx +1 -1
  223. package/examples/{public-pages → features/public-pages}/PublicPageUsageExample.tsx +1 -1
  224. package/examples/index.ts +11 -3
  225. package/package.json +30 -10
  226. package/src/components/Alert/Alert.tsx +1 -1
  227. package/src/components/Avatar/Avatar.tsx +1 -1
  228. package/src/components/Button/Button.tsx +1 -1
  229. package/src/components/Card/Card.tsx +1 -1
  230. package/src/components/Checkbox/Checkbox.tsx +1 -1
  231. package/src/components/DataTable/DataTable.test.tsx +1 -1
  232. package/src/components/DataTable/DataTable.tsx +1 -30
  233. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +562 -0
  234. package/src/components/DataTable/__tests__/styles.test.ts +2 -2
  235. package/src/components/DataTable/components/ActionButtons.tsx +0 -15
  236. package/src/components/DataTable/components/DataTableCore.tsx +4 -185
  237. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +1 -1
  238. package/src/components/DataTable/components/DataTableModals.tsx +1 -27
  239. package/src/components/DataTable/components/EditableRow.tsx +1 -1
  240. package/src/components/DataTable/components/ImportModal.tsx +2 -14
  241. package/src/components/DataTable/components/PaginationControls.tsx +1 -1
  242. package/src/components/DataTable/components/UnifiedTableBody.tsx +109 -82
  243. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +1 -1
  244. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +1 -1
  245. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +1 -1
  246. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +1 -1
  247. package/src/components/DataTable/examples/GroupingAggregationExample.tsx +273 -0
  248. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +1 -1
  249. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +1 -1
  250. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +1 -1
  251. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +1 -1
  252. package/src/components/DataTable/hooks/useDataTablePermissions.ts +2 -23
  253. package/src/components/DataTable/index.ts +4 -0
  254. package/src/components/DataTable/styles.ts +1 -1
  255. package/src/components/DataTable/types.ts +13 -0
  256. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +1 -1
  257. package/src/components/DataTable/utils/aggregationUtils.ts +161 -0
  258. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  259. package/src/components/DataTable/utils/flexibleImport.ts +1 -11
  260. package/src/components/DataTable/utils/index.ts +1 -0
  261. package/src/components/DataTable/utils/paginationUtils.ts +1 -1
  262. package/src/components/Dialog/Dialog.tsx +2 -2
  263. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +35 -7
  264. package/src/components/ErrorBoundary/ErrorBoundary.tsx +5 -4
  265. package/src/components/EventSelector/EventSelector.tsx +3 -2
  266. package/src/components/FileDisplay/FileDisplay.tsx +2 -36
  267. package/src/components/FileUpload/FileUpload.test.tsx +2 -2
  268. package/src/components/FileUpload/FileUpload.tsx +2 -2
  269. package/src/components/Footer/Footer.tsx +1 -1
  270. package/src/components/Form/Form.test.tsx +4 -509
  271. package/src/components/Form/Form.tsx +1 -1
  272. package/src/components/Form/FormField.tsx +1 -1
  273. package/src/components/Form/index.ts +0 -12
  274. package/src/components/Header/Header.tsx +1 -1
  275. package/src/components/Input/Input.tsx +1 -1
  276. package/src/components/Label/Label.tsx +1 -1
  277. package/src/components/LoginForm/LoginForm.tsx +1 -1
  278. package/src/components/NavigationMenu/NavigationMenu.test.tsx +19 -3
  279. package/src/components/NavigationMenu/NavigationMenu.tsx +9 -8
  280. package/src/components/OrganisationSelector/OrganisationSelector.tsx +4 -3
  281. package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -12
  282. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.integration.test.tsx +0 -16
  283. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.security.test.tsx +0 -1
  284. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -9
  285. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +35 -3
  286. package/src/components/PaceLoginPage/PaceLoginPage.tsx +13 -12
  287. package/src/components/PasswordReset/PasswordChangeForm.tsx +1 -1
  288. package/src/components/PasswordReset/index.ts +0 -2
  289. package/src/components/Progress/Progress.tsx +1 -1
  290. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +35 -8
  291. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -2
  292. package/src/components/PublicLayout/PublicErrorBoundary.tsx +1 -1
  293. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +1 -1
  294. package/src/components/PublicLayout/PublicPageContextChecker.tsx +44 -43
  295. package/src/components/PublicLayout/PublicPageFooter.tsx +1 -1
  296. package/src/components/PublicLayout/PublicPageHeader.tsx +1 -15
  297. package/src/components/PublicLayout/PublicPageProvider.tsx +3 -2
  298. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +2 -0
  299. package/src/components/PublicLayout/index.ts +4 -2
  300. package/src/components/Select/Select.tsx +1 -1
  301. package/src/components/{SessionRestorationLoader.tsx → SessionRestorationLoader/SessionRestorationLoader.tsx} +3 -2
  302. package/src/components/SessionRestorationLoader/index.ts +3 -0
  303. package/src/components/Switch/Switch.tsx +1 -1
  304. package/src/components/Table/Table.tsx +1 -1
  305. package/src/components/Toast/Toast.tsx +1 -1
  306. package/src/components/Tooltip/Tooltip.tsx +1 -1
  307. package/src/components/index.ts +4 -10
  308. package/src/hooks/__tests__/hooks.integration.test.tsx +37 -22
  309. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +33 -17
  310. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +28 -3
  311. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +36 -9
  312. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +26 -2
  313. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +19 -6
  314. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -4
  315. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +17 -4
  316. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +26 -6
  317. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +16 -6
  318. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +3 -3
  319. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +17 -3
  320. package/src/hooks/public/usePublicEvent.ts +7 -6
  321. package/src/hooks/public/usePublicEventLogo.ts +7 -4
  322. package/src/hooks/public/usePublicFileDisplay.ts +6 -150
  323. package/src/hooks/useComponentPerformance.ts +4 -1
  324. package/src/hooks/useDataTablePerformance.ts +4 -3
  325. package/src/hooks/useEventTheme.test.ts +18 -5
  326. package/src/hooks/useEventTheme.ts +4 -1
  327. package/src/hooks/useEvents.ts +2 -0
  328. package/src/hooks/useFileDisplay.ts +9 -8
  329. package/src/hooks/useFileReference.ts +4 -1
  330. package/src/hooks/useFileUrl.ts +4 -1
  331. package/src/hooks/useInactivityTracker.ts +5 -4
  332. package/src/hooks/useOrganisationSecurity.test.ts +33 -12
  333. package/src/hooks/useOrganisationSecurity.ts +8 -7
  334. package/src/hooks/usePerformanceMonitor.ts +6 -3
  335. package/src/hooks/usePermissionCache.ts +13 -6
  336. package/src/hooks/useSecureDataAccess.test.ts +2 -2
  337. package/src/hooks/useSecureDataAccess.ts +9 -8
  338. package/src/hooks/useSessionRestoration.ts +4 -1
  339. package/src/hooks/useStorage.ts +4 -1
  340. package/src/index.ts +16 -7
  341. package/src/providers/services/AuthServiceProvider.tsx +3 -2
  342. package/src/providers/services/EventServiceProvider.tsx +2 -1
  343. package/src/providers/services/InactivityServiceProvider.tsx +2 -1
  344. package/src/providers/services/OrganisationServiceProvider.tsx +2 -1
  345. package/src/providers/services/UnifiedAuthProvider.tsx +4 -3
  346. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +22 -2
  347. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +24 -2
  348. package/src/rbac/__tests__/cache-invalidation.test.ts +20 -6
  349. package/src/rbac/api.ts +5 -2
  350. package/src/rbac/audit-enhanced.ts +6 -6
  351. package/src/rbac/audit.test.ts +60 -38
  352. package/src/rbac/audit.ts +8 -8
  353. package/src/rbac/cache-invalidation.ts +7 -4
  354. package/src/rbac/components/EnhancedNavigationMenu.tsx +11 -5
  355. package/src/rbac/components/NavigationGuard.tsx +7 -3
  356. package/src/rbac/components/NavigationProvider.tsx +6 -3
  357. package/src/rbac/components/PagePermissionGuard.tsx +28 -16
  358. package/src/rbac/components/PagePermissionProvider.tsx +4 -1
  359. package/src/rbac/components/PermissionEnforcer.tsx +9 -3
  360. package/src/rbac/components/RoleBasedRouter.tsx +3 -1
  361. package/src/rbac/components/SecureDataProvider.tsx +7 -3
  362. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +87 -61
  363. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +83 -33
  364. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +36 -13
  365. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +2 -2
  366. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +22 -8
  367. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +19 -6
  368. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +43 -17
  369. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +42 -17
  370. package/src/rbac/engine.ts +15 -7
  371. package/src/rbac/hooks/usePermissions.ts +7 -3
  372. package/src/rbac/hooks/useResolvedScope.test.ts +2 -2
  373. package/src/rbac/hooks/useResolvedScope.ts +10 -7
  374. package/src/rbac/permissions.ts +5 -2
  375. package/src/rbac/security.test.ts +27 -16
  376. package/src/rbac/security.ts +5 -4
  377. package/src/services/AuthService.ts +22 -21
  378. package/src/services/EventService.ts +12 -12
  379. package/src/services/InactivityService.ts +5 -4
  380. package/src/services/OrganisationService.ts +26 -25
  381. package/src/services/__tests__/AuthService.test.ts +51 -19
  382. package/src/services/__tests__/EventService.test.ts +37 -5
  383. package/src/services/__tests__/InactivityService.test.ts +38 -4
  384. package/src/services/__tests__/OrganisationService.test.ts +3 -8
  385. package/src/services/base/BaseService.ts +3 -1
  386. package/src/theming/__tests__/runtime.test.ts +21 -12
  387. package/src/theming/parseEventColours.ts +5 -19
  388. package/src/theming/runtime.ts +8 -4
  389. package/src/types/validation.ts +2 -29
  390. package/src/utils/__tests__/appConfig.unit.test.ts +1 -1
  391. package/src/utils/__tests__/audit.unit.test.ts +1 -1
  392. package/src/utils/__tests__/auth-utils.unit.test.ts +1 -1
  393. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +19 -19
  394. package/src/utils/__tests__/cn.unit.test.ts +1 -1
  395. package/src/utils/__tests__/debugLogger.test.ts +1 -1
  396. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +1 -1
  397. package/src/utils/__tests__/dynamicUtils.unit.test.ts +1 -1
  398. package/src/utils/__tests__/formatting.unit.test.ts +1 -1
  399. package/src/utils/__tests__/lazyLoad.unit.test.tsx +1 -1
  400. package/src/utils/__tests__/logger.unit.test.ts +1 -1
  401. package/src/utils/__tests__/organisationContext.unit.test.ts +1 -1
  402. package/src/utils/__tests__/performanceBenchmark.test.ts +1 -1
  403. package/src/utils/__tests__/performanceBudgets.unit.test.ts +1 -1
  404. package/src/utils/__tests__/permissionTypes.unit.test.ts +1 -1
  405. package/src/utils/__tests__/permissionUtils.unit.test.ts +1 -1
  406. package/src/utils/__tests__/sanitization.unit.test.ts +1 -1
  407. package/src/utils/__tests__/schemaUtils.unit.test.ts +1 -1
  408. package/src/utils/__tests__/secureDataAccess.unit.test.ts +1 -1
  409. package/src/utils/__tests__/secureErrors.unit.test.ts +33 -15
  410. package/src/utils/__tests__/secureStorage.unit.test.ts +1 -1
  411. package/src/utils/__tests__/security.unit.test.ts +40 -18
  412. package/src/utils/__tests__/securityMonitor.unit.test.ts +1 -1
  413. package/src/utils/__tests__/sessionTracking.unit.test.ts +40 -29
  414. package/src/utils/__tests__/validationUtils.unit.test.ts +19 -6
  415. package/src/utils/{appIdResolver.test.ts → app/appIdResolver.test.ts} +28 -30
  416. package/src/utils/{appIdResolver.ts → app/appIdResolver.ts} +8 -5
  417. package/src/utils/{appNameResolver.test.ts → app/appNameResolver.test.ts} +1 -1
  418. package/src/utils/{appNameResolver.ts → app/appNameResolver.ts} +5 -1
  419. package/src/utils/{organisationContext.ts → context/organisationContext.ts} +6 -3
  420. package/src/utils/{sessionTracking.ts → context/sessionTracking.ts} +11 -12
  421. package/src/utils/{logger.ts → core/logger.ts} +4 -2
  422. package/src/utils/{deviceFingerprint.ts → device/deviceFingerprint.ts} +1 -1
  423. package/src/utils/{lazyLoad.tsx → dynamic/lazyLoad.tsx} +2 -2
  424. package/src/utils/{file-reference.test.ts → file-reference/__tests__/file-reference.test.ts} +5 -5
  425. package/src/utils/{file-reference.ts → file-reference/index.ts} +20 -38
  426. package/src/utils/index.ts +32 -54
  427. package/src/utils/{secureErrors.ts → security/secureErrors.ts} +6 -3
  428. package/src/utils/{security.ts → security/security.ts} +5 -2
  429. package/src/utils/storage/__tests__/helpers.unit.test.ts +1 -4
  430. package/src/utils/storage/helpers.ts +15 -8
  431. package/src/{components/Dialog/utils/__tests__/safeHtml.unit.test.ts → utils/validation/__tests__/htmlSanitization.unit.test.ts} +9 -15
  432. package/src/{validation → utils/validation}/csrf.ts +1 -1
  433. package/src/{components/Dialog/utils/safeHtml.ts → utils/validation/htmlSanitization.ts} +9 -10
  434. package/src/utils/validation/index.ts +79 -0
  435. package/src/utils/{sanitization.ts → validation/sanitization.ts} +71 -2
  436. package/src/{validation/schemaUtils.ts → utils/validation/schema.ts} +11 -6
  437. package/src/{validation → utils/validation}/sqlInjectionProtection.ts +2 -0
  438. package/src/utils/{validationUtils.ts → validation/validationUtils.ts} +4 -1
  439. package/src/validation/index.ts +3 -34
  440. package/dist/UnifiedAuthProvider-CQDZRJIS.js +0 -16
  441. package/dist/chunk-24MKLB7U.js +0 -81
  442. package/dist/chunk-24MKLB7U.js.map +0 -1
  443. package/dist/chunk-3CG5L6RN.js.map +0 -1
  444. package/dist/chunk-3DBFLLLU.js.map +0 -1
  445. package/dist/chunk-5F3NDPJV.js.map +0 -1
  446. package/dist/chunk-66C4BSAY.js.map +0 -1
  447. package/dist/chunk-BDZUMRBD.js.map +0 -1
  448. package/dist/chunk-BYXRHAIF.js.map +0 -1
  449. package/dist/chunk-CDQ3PX7L.js +0 -18
  450. package/dist/chunk-CDQ3PX7L.js.map +0 -1
  451. package/dist/chunk-CQZU6TFE.js.map +0 -1
  452. package/dist/chunk-F64FFPOZ.js.map +0 -1
  453. package/dist/chunk-GEVIB2UB.js.map +0 -1
  454. package/dist/chunk-GKHF54DI.js.map +0 -1
  455. package/dist/chunk-GVDR7WNV.js.map +0 -1
  456. package/dist/chunk-HMNOSGVA.js.map +0 -1
  457. package/dist/chunk-JCQZ6LA7.js.map +0 -1
  458. package/dist/chunk-M6DDYFUD.js.map +0 -1
  459. package/dist/chunk-O3NWNXDY.js.map +0 -1
  460. package/dist/chunk-PYUXFQJ3.js.map +0 -1
  461. package/dist/chunk-UJI6WSMD.js.map +0 -1
  462. package/dist/chunk-VZ5OR6HD.js.map +0 -1
  463. package/dist/chunk-WP5I5GLN.js.map +0 -1
  464. package/dist/chunk-ZYZCRSBD.js.map +0 -1
  465. package/src/components/Dialog/README.md +0 -804
  466. package/src/components/Form/FormErrorSummary.tsx +0 -113
  467. package/src/components/Form/FormFieldset.tsx +0 -127
  468. package/src/components/Form/FormLiveRegion.tsx +0 -198
  469. package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
  470. package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
  471. package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
  472. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
  473. package/src/components/PublicLayout/__tests__/PublicPageDebugger.test.tsx +0 -185
  474. package/src/examples/CorrectPublicPageImplementation.tsx +0 -304
  475. package/src/examples/PublicEventPage.tsx +0 -287
  476. package/src/examples/PublicPageApp.tsx +0 -321
  477. package/src/examples/PublicPageUsageExample.tsx +0 -218
  478. package/src/utils/schemaUtils.ts +0 -37
  479. package/src/validation/__tests__/common.unit.test.ts +0 -101
  480. package/src/validation/__tests__/csrf.unit.test.ts +0 -365
  481. package/src/validation/__tests__/passwordSchema.unit.test.ts +0 -203
  482. package/src/validation/__tests__/sanitization.unit.test.ts +0 -250
  483. package/src/validation/__tests__/schemaUtils.unit.test.ts +0 -451
  484. package/src/validation/__tests__/sqlInjectionProtection.unit.test.ts +0 -462
  485. package/src/validation/__tests__/user.unit.test.ts +0 -440
  486. package/src/validation/sanitization.ts +0 -96
  487. /package/dist/{DataTable-A36PJG6N.js.map → DataTable-CYOHOX3O.js.map} +0 -0
  488. /package/dist/{UnifiedAuthProvider-CQDZRJIS.js.map → UnifiedAuthProvider-5E5TUNMS.js.map} +0 -0
  489. /package/dist/{api-TNIBJWLM.js.map → api-45XYYO2A.js.map} +0 -0
  490. /package/dist/{audit-T36HM7IM.js.map → audit-64X3VJXB.js.map} +0 -0
  491. /package/dist/{chunk-CTJRBUX2.js.map → chunk-2TWNJ46Y.js.map} +0 -0
  492. /package/dist/{chunk-ZV77RZMU.js.map → chunk-XARJS7CD.js.map} +0 -0
  493. /package/dist/{useInactivityTracker-MRUU55XI.js.map → useInactivityTracker-TO6ZOF35.js.map} +0 -0
  494. /package/examples/{public-pages → features/public-pages}/index.ts +0 -0
  495. /package/examples/{RBAC → features/rbac}/CompleteRBACExample.tsx +0 -0
  496. /package/examples/{RBAC → features/rbac}/EventBasedApp.tsx +0 -0
  497. /package/examples/{RBAC → features/rbac}/PermissionExample.tsx +0 -0
  498. /package/examples/{RBAC → features/rbac}/index.ts +0 -0
  499. /package/src/utils/{appConfig.ts → app/appConfig.ts} +0 -0
  500. /package/src/utils/{appNameResolver.simple.test.ts → app/appNameResolver.simple.test.ts} +0 -0
  501. /package/src/utils/{audit.ts → audit/audit.ts} +0 -0
  502. /package/src/utils/{organisationContext.test.ts → context/organisationContext.test.ts} +0 -0
  503. /package/src/utils/{cn.ts → core/cn.ts} +0 -0
  504. /package/src/utils/{debugLogger.ts → core/debugLogger.ts} +0 -0
  505. /package/src/utils/{dynamicUtils.ts → dynamic/dynamicUtils.ts} +0 -0
  506. /package/src/utils/{formatDate.test.ts → formatting/formatDate.test.ts} +0 -0
  507. /package/src/utils/{formatting.ts → formatting/formatting.ts} +0 -0
  508. /package/src/utils/{bundleAnalysis.ts → performance/bundleAnalysis.ts} +0 -0
  509. /package/src/utils/{performanceBenchmark.ts → performance/performanceBenchmark.ts} +0 -0
  510. /package/src/utils/{performanceBudgets.ts → performance/performanceBudgets.ts} +0 -0
  511. /package/src/utils/{permissionTypes.ts → permissions/permissionTypes.ts} +0 -0
  512. /package/src/utils/{permissionUtils.test.ts → permissions/permissionUtils.test.ts} +0 -0
  513. /package/src/utils/{permissionUtils.ts → permissions/permissionUtils.ts} +0 -0
  514. /package/src/utils/{auth-utils.ts → security/auth-utils.ts} +0 -0
  515. /package/src/utils/{secureDataAccess.test.ts → security/secureDataAccess.test.ts} +0 -0
  516. /package/src/utils/{secureDataAccess.ts → security/secureDataAccess.ts} +0 -0
  517. /package/src/utils/{secureStorage.ts → security/secureStorage.ts} +0 -0
  518. /package/src/utils/{securityMonitor.ts → security/securityMonitor.ts} +0 -0
  519. /package/src/{validation → utils/validation}/common.ts +0 -0
  520. /package/src/{validation → utils/validation}/passwordSchema.ts +0 -0
  521. /package/src/{validation → utils/validation}/user.ts +0 -0
  522. /package/src/utils/{validation.ts → validation/validation.ts} +0 -0
@@ -1,365 +0,0 @@
1
- /**
2
- * @file CSRF Protection Unit Tests
3
- * @package @jmruthers/pace-core
4
- * @module Validation/CSRF/Tests
5
- * @since 0.1.0
6
- */
7
-
8
- import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
9
- import {
10
- generateCSRFToken,
11
- validateCSRFToken,
12
- getCSRFToken,
13
- csrfManager,
14
- CSRFTokenData,
15
- } from '../csrf';
16
-
17
- // Mock crypto for testing
18
- const mockCrypto = {
19
- getRandomValues: vi.fn(),
20
- };
21
-
22
- Object.defineProperty(global, 'crypto', {
23
- value: mockCrypto,
24
- writable: true,
25
- });
26
-
27
- // Mock secure storage
28
- vi.mock('../../utils/secureStorage', () => ({
29
- secureStorage: {
30
- setItem: vi.fn().mockResolvedValue(undefined),
31
- getItem: vi.fn().mockResolvedValue(null),
32
- removeItem: vi.fn().mockResolvedValue(undefined),
33
- },
34
- }));
35
-
36
- describe('CSRF Protection', () => {
37
- const testSessionId = 'test-session-123';
38
- const testSessionId2 = 'test-session-456';
39
-
40
- beforeEach(() => {
41
- vi.clearAllMocks();
42
- mockCrypto.getRandomValues.mockImplementation((array) => {
43
- for (let i = 0; i < array.length; i++) {
44
- array[i] = Math.floor(Math.random() * 256);
45
- }
46
- return array;
47
- });
48
- });
49
-
50
- afterEach(async () => {
51
- // Clear session tokens
52
- await csrfManager.clearSession(testSessionId);
53
- await csrfManager.clearSession(testSessionId2);
54
- });
55
-
56
- describe('generateCSRFToken', () => {
57
- it('should generate a valid CSRF token', async () => {
58
- const token = await generateCSRFToken(testSessionId);
59
-
60
- expect(token).toBeDefined();
61
- expect(typeof token).toBe('string');
62
- expect(token.length).toBe(64); // 32 bytes * 2 hex chars
63
- });
64
-
65
- it('should generate different tokens on subsequent calls', async () => {
66
- const token1 = await generateCSRFToken(testSessionId);
67
- const token2 = await generateCSRFToken(testSessionId);
68
-
69
- expect(token1).not.toBe(token2);
70
- });
71
-
72
- it('should generate tokens for different sessions', async () => {
73
- const token1 = await generateCSRFToken(testSessionId);
74
- const token2 = await generateCSRFToken(testSessionId2);
75
-
76
- expect(token1).not.toBe(token2);
77
- });
78
-
79
- it('should handle crypto.getRandomValues errors', async () => {
80
- mockCrypto.getRandomValues.mockImplementation(() => {
81
- throw new Error('Crypto unavailable');
82
- });
83
-
84
- await expect(generateCSRFToken(testSessionId)).rejects.toThrow('CSRF token generation failed');
85
- });
86
- });
87
-
88
- describe('validateCSRFToken', () => {
89
- it('should validate a valid token for correct session', async () => {
90
- const token = await generateCSRFToken(testSessionId);
91
- const isValid = await validateCSRFToken(token, testSessionId);
92
-
93
- expect(isValid).toBe(true);
94
- });
95
-
96
- it('should reject token for wrong session', async () => {
97
- const token = await generateCSRFToken(testSessionId);
98
- const isValid = await validateCSRFToken(token, testSessionId2);
99
-
100
- expect(isValid).toBe(false);
101
- });
102
-
103
- it('should reject invalid token format', async () => {
104
- const invalidToken = 'invalid-token';
105
- const isValid = await validateCSRFToken(invalidToken, testSessionId);
106
-
107
- expect(isValid).toBe(false);
108
- });
109
-
110
- it('should reject reused tokens (one-time use)', async () => {
111
- const token = await generateCSRFToken(testSessionId);
112
-
113
- // First use should succeed
114
- const firstUse = await validateCSRFToken(token, testSessionId);
115
- expect(firstUse).toBe(true);
116
-
117
- // Second use should fail
118
- const secondUse = await validateCSRFToken(token, testSessionId);
119
- expect(secondUse).toBe(false);
120
- });
121
-
122
- it('should handle empty or null tokens', async () => {
123
- expect(await validateCSRFToken('', testSessionId)).toBe(false);
124
- expect(await validateCSRFToken(null as any, testSessionId)).toBe(false);
125
- expect(await validateCSRFToken(undefined as any, testSessionId)).toBe(false);
126
- });
127
- });
128
-
129
- describe('getCSRFToken', () => {
130
- it('should return existing valid token for session', async () => {
131
- const generatedToken = await generateCSRFToken(testSessionId);
132
- const retrievedToken = await getCSRFToken(testSessionId);
133
-
134
- expect(retrievedToken).toBeDefined();
135
- expect(typeof retrievedToken).toBe('string');
136
- });
137
-
138
- it('should generate new token if none exists', async () => {
139
- const token = await getCSRFToken(testSessionId);
140
-
141
- expect(token).toBeDefined();
142
- expect(typeof token).toBe('string');
143
- expect(token!.length).toBe(64);
144
- });
145
-
146
- it('should return different tokens for different sessions', async () => {
147
- const token1 = await getCSRFToken(testSessionId);
148
- const token2 = await getCSRFToken(testSessionId2);
149
-
150
- expect(token1).not.toBe(token2);
151
- });
152
- });
153
-
154
- describe('csrfManager', () => {
155
- it('should manage multiple sessions', async () => {
156
- const token1 = await csrfManager.generateToken(testSessionId);
157
- const token2 = await csrfManager.generateToken(testSessionId2);
158
-
159
- expect(await csrfManager.validateToken(token1, testSessionId)).toBe(true);
160
- expect(await csrfManager.validateToken(token2, testSessionId2)).toBe(true);
161
-
162
- // Cross-session validation should fail
163
- expect(await csrfManager.validateToken(token1, testSessionId2)).toBe(false);
164
- expect(await csrfManager.validateToken(token2, testSessionId)).toBe(false);
165
- });
166
-
167
- it('should clear session tokens', async () => {
168
- const token = await csrfManager.generateToken(testSessionId);
169
-
170
- // Token should be valid
171
- expect(await csrfManager.validateToken(token, testSessionId)).toBe(true);
172
-
173
- // Clear session
174
- await csrfManager.clearSession(testSessionId);
175
-
176
- // Token should no longer be valid
177
- expect(await csrfManager.validateToken(token, testSessionId)).toBe(false);
178
- });
179
-
180
- it('should handle getCurrentToken for existing session', async () => {
181
- await csrfManager.generateToken(testSessionId);
182
- const currentToken = await csrfManager.getCurrentToken(testSessionId);
183
-
184
- expect(currentToken).toBeDefined();
185
- expect(typeof currentToken).toBe('string');
186
- });
187
-
188
- it('should handle getCurrentToken for new session', async () => {
189
- const currentToken = await csrfManager.getCurrentToken('new-session-789');
190
-
191
- expect(currentToken).toBeDefined();
192
- expect(typeof currentToken).toBe('string');
193
- expect(currentToken!.length).toBe(64);
194
- });
195
- });
196
-
197
- describe('Token Lifecycle and Expiry', () => {
198
- it('should handle token expiry', async () => {
199
- // Mock Date.now to simulate time passage
200
- const originalNow = Date.now;
201
- const mockNow = vi.fn();
202
- Date.now = mockNow;
203
-
204
- try {
205
- const initialTime = 1000000;
206
- mockNow.mockReturnValue(initialTime);
207
-
208
- const token = await generateCSRFToken(testSessionId);
209
-
210
- // Token should be valid immediately
211
- expect(await validateCSRFToken(token, testSessionId)).toBe(true);
212
-
213
- // Regenerate token since it was consumed
214
- const token2 = await generateCSRFToken(testSessionId);
215
-
216
- // Simulate time passage beyond expiry (30 minutes + 1 second)
217
- mockNow.mockReturnValue(initialTime + (30 * 60 * 1000) + 1000);
218
-
219
- // Token should now be expired
220
- expect(await validateCSRFToken(token2, testSessionId)).toBe(false);
221
- } finally {
222
- Date.now = originalNow;
223
- }
224
- });
225
- });
226
-
227
- describe('Security Features', () => {
228
- it('should limit tokens per session', async () => {
229
- // Generate maximum tokens for session
230
- const tokens: string[] = [];
231
- for (let i = 0; i < 15; i++) { // More than MAX_TOKENS_PER_SESSION (10)
232
- const token = await generateCSRFToken(testSessionId);
233
- tokens.push(token);
234
- }
235
-
236
- expect(tokens.length).toBe(15);
237
- expect(new Set(tokens).size).toBe(15); // All should be unique
238
- });
239
-
240
- it('should use cryptographically secure random values', async () => {
241
- const calledValues: Uint8Array[] = [];
242
- mockCrypto.getRandomValues.mockImplementation((array) => {
243
- calledValues.push(new Uint8Array(array));
244
- for (let i = 0; i < array.length; i++) {
245
- array[i] = i % 256; // Deterministic but different values
246
- }
247
- return array;
248
- });
249
-
250
- await generateCSRFToken(testSessionId);
251
-
252
- expect(mockCrypto.getRandomValues).toHaveBeenCalledTimes(1);
253
- expect(calledValues[0].length).toBe(32); // 32 bytes
254
- });
255
- });
256
-
257
- describe('Error Handling', () => {
258
- it('should handle storage failures gracefully', async () => {
259
- // Mock storage to fail
260
- const { secureStorage } = await import('../../utils/secureStorage');
261
- vi.mocked(secureStorage.setItem).mockRejectedValue(new Error('Storage failed'));
262
-
263
- // Should still generate token despite storage failure
264
- const token = await generateCSRFToken(testSessionId);
265
- expect(token).toBeDefined();
266
- });
267
-
268
- it('should handle storage retrieval failures', async () => {
269
- const { secureStorage } = await import('../../utils/secureStorage');
270
- vi.mocked(secureStorage.getItem).mockRejectedValue(new Error('Retrieval failed'));
271
-
272
- // Should still work by creating new tokens
273
- const token = await getCSRFToken(testSessionId);
274
- expect(token).toBeDefined();
275
- });
276
-
277
- it('should handle malformed stored data', async () => {
278
- const { secureStorage } = await import('../../utils/secureStorage');
279
- vi.mocked(secureStorage.getItem).mockResolvedValue('invalid-json');
280
-
281
- // Should clear cache and continue working
282
- const token = await getCSRFToken(testSessionId);
283
- expect(token).toBeDefined();
284
- });
285
- });
286
-
287
- describe('Type Safety', () => {
288
- it('should have correct CSRFTokenData interface', () => {
289
- const tokenData: CSRFTokenData = {
290
- token: 'test-token',
291
- sessionId: 'test-session',
292
- timestamp: Date.now(),
293
- used: false,
294
- };
295
-
296
- expect(tokenData.token).toBe('test-token');
297
- expect(tokenData.sessionId).toBe('test-session');
298
- expect(typeof tokenData.timestamp).toBe('number');
299
- expect(typeof tokenData.used).toBe('boolean');
300
- });
301
- });
302
-
303
- describe('Edge Cases', () => {
304
- it('should handle very long session IDs', async () => {
305
- const longSessionId = 'a'.repeat(500);
306
- const token = await generateCSRFToken(longSessionId);
307
-
308
- expect(token).toBeDefined();
309
- expect(token.length).toBe(64);
310
-
311
- // Should be valid for that session
312
- const isValid = await validateCSRFToken(token, longSessionId);
313
- expect(isValid).toBe(true);
314
- });
315
-
316
- it('should handle rapid token generation', async () => {
317
- const tokens = await Promise.all(
318
- Array.from({ length: 20 }, () => generateCSRFToken(testSessionId))
319
- );
320
-
321
- expect(tokens).toHaveLength(20);
322
- // All should be unique 32-byte tokens
323
- const uniqueTokens = new Set(tokens);
324
- expect(uniqueTokens.size).toBe(20);
325
-
326
- // Last token should be valid
327
- const lastToken = tokens[tokens.length - 1];
328
- expect(await validateCSRFToken(lastToken, testSessionId)).toBe(true);
329
- });
330
-
331
- it('should handle storage corruption by clearing cache', async () => {
332
- const { secureStorage } = await import('../../utils/secureStorage');
333
-
334
- // Simulate malformed storage data
335
- vi.mocked(secureStorage.getItem).mockResolvedValueOnce('{{invalid json}');
336
-
337
- // Should handle gracefully and generate new token
338
- const token = await getCSRFToken(testSessionId);
339
- expect(token).toBeDefined();
340
- expect(typeof token).toBe('string');
341
- });
342
-
343
- it('should handle concurrent token generation safely', async () => {
344
- const promises = Array.from({ length: 10 }, (_, i) =>
345
- generateCSRFToken(`session-${i}`)
346
- );
347
-
348
- const tokens = await Promise.all(promises);
349
-
350
- expect(tokens).toHaveLength(10);
351
- expect(new Set(tokens).size).toBe(10);
352
- });
353
-
354
- it('should handle session ID collision edge cases', async () => {
355
- const sameSession = 'collision-session';
356
-
357
- const token1 = await generateCSRFToken(sameSession);
358
- const token2 = await generateCSRFToken(sameSession);
359
-
360
- // Both should be valid for same session
361
- expect(await validateCSRFToken(token1, sameSession)).toBe(true);
362
- expect(await validateCSRFToken(token2, sameSession)).toBe(true);
363
- });
364
- });
365
- });
@@ -1,203 +0,0 @@
1
- import { describe, it, expect } from 'vitest';
2
- import { passwordSchema, securePasswordSchema, calculatePasswordStrength } from '../passwordSchema';
3
-
4
- describe('Password Validation Schemas', () => {
5
- describe('passwordSchema (Basic)', () => {
6
- it('should validate passwords with minimum length', () => {
7
- expect(passwordSchema.safeParse('123456').success).toBe(true);
8
- expect(passwordSchema.safeParse('password').success).toBe(true);
9
- expect(passwordSchema.safeParse('StrongPass123!').success).toBe(true);
10
- });
11
-
12
- it('should reject passwords that are too short', () => {
13
- expect(passwordSchema.safeParse('12345').success).toBe(false);
14
- expect(passwordSchema.safeParse('').success).toBe(false);
15
- });
16
-
17
- it('should reject passwords that are too long', () => {
18
- const longPassword = 'a'.repeat(129);
19
- expect(passwordSchema.safeParse(longPassword).success).toBe(false);
20
- });
21
- });
22
-
23
- describe('securePasswordSchema (Strict)', () => {
24
- it('should validate strong passwords', () => {
25
- expect(securePasswordSchema.safeParse('StrongPass123!').success).toBe(true);
26
- expect(securePasswordSchema.safeParse('Complex@Password1').success).toBe(true);
27
- expect(securePasswordSchema.safeParse('MySecureP@ssw0rd').success).toBe(true);
28
- });
29
-
30
- it('should reject weak passwords', () => {
31
- expect(securePasswordSchema.safeParse('weak').success).toBe(false);
32
- expect(securePasswordSchema.safeParse('12345678').success).toBe(false);
33
- expect(securePasswordSchema.safeParse('').success).toBe(false);
34
- });
35
-
36
- it('should reject passwords without uppercase letters', () => {
37
- expect(securePasswordSchema.safeParse('password123!').success).toBe(false);
38
- });
39
-
40
- it('should reject passwords without lowercase letters', () => {
41
- expect(securePasswordSchema.safeParse('PASSWORD123!').success).toBe(false);
42
- });
43
-
44
- it('should reject passwords without numbers', () => {
45
- expect(securePasswordSchema.safeParse('Password!').success).toBe(false);
46
- });
47
-
48
- it('should reject passwords without special characters', () => {
49
- expect(securePasswordSchema.safeParse('Password123').success).toBe(false);
50
- });
51
-
52
- it('should reject passwords that are too short', () => {
53
- expect(securePasswordSchema.safeParse('Pass1!').success).toBe(false);
54
- });
55
-
56
- it('should reject common passwords', () => {
57
- expect(securePasswordSchema.safeParse('password').success).toBe(false);
58
- expect(securePasswordSchema.safeParse('123456').success).toBe(false);
59
- expect(securePasswordSchema.safeParse('qwerty').success).toBe(false);
60
- });
61
-
62
- it('should provide meaningful error messages', () => {
63
- const result = securePasswordSchema.safeParse('weak');
64
- expect(result.success).toBe(false);
65
- if (!result.success) {
66
- expect(result.error.issues.length).toBeGreaterThan(0);
67
- }
68
- });
69
- });
70
-
71
- describe('calculatePasswordStrength', () => {
72
- it('should calculate strength for strong passwords', () => {
73
- const result = calculatePasswordStrength('StrongPass123!');
74
- expect(result.score).toBeGreaterThan(70);
75
- expect(result.level).toBe('strong');
76
- expect(result.feedback).toHaveLength(0);
77
- });
78
-
79
- it('should calculate strength for weak passwords', () => {
80
- const result = calculatePasswordStrength('weak');
81
- expect(result.score).toBeLessThan(50);
82
- expect(result.level).toBe('very-weak');
83
- expect(result.feedback.length).toBeGreaterThan(0);
84
- });
85
-
86
- it('should provide feedback for improvement', () => {
87
- const result = calculatePasswordStrength('password');
88
- expect(result.feedback).toContain('Add uppercase letters');
89
- expect(result.feedback).toContain('Add numbers');
90
- expect(result.feedback).toContain('Add special characters');
91
- });
92
-
93
- it('should penalize common passwords', () => {
94
- const result = calculatePasswordStrength('password');
95
- expect(result.feedback).toContain('Avoid common passwords');
96
- });
97
- });
98
-
99
- describe('Edge Cases', () => {
100
- it('should handle empty string password', () => {
101
- expect(passwordSchema.safeParse('').success).toBe(false);
102
- expect(securePasswordSchema.safeParse('').success).toBe(false);
103
- });
104
-
105
- it('should handle whitespace-only passwords', () => {
106
- expect(passwordSchema.safeParse(' ').success).toBe(true);
107
- expect(securePasswordSchema.safeParse(' ').success).toBe(false);
108
- });
109
-
110
- it('should handle exactly 6 character passwords', () => {
111
- expect(passwordSchema.safeParse('123456').success).toBe(true);
112
- expect(securePasswordSchema.safeParse('123456').success).toBe(false);
113
- });
114
-
115
- it('should handle exactly 128 character passwords', () => {
116
- const password = 'a'.repeat(128);
117
- expect(passwordSchema.safeParse(password).success).toBe(true);
118
- expect(securePasswordSchema.safeParse(password).success).toBe(false);
119
- });
120
-
121
- it('should handle unicode passwords', () => {
122
- const unicodePassword = 'Test🔒Pass123!';
123
- expect(passwordSchema.safeParse(unicodePassword).success).toBe(true);
124
- // Secure schema might not pass if unicode doesn't include uppercase/numbers
125
- });
126
-
127
- it('should handle passwords with special unicode characters', () => {
128
- const password = 'Pass123😊!';
129
- expect(passwordSchema.safeParse(password).success).toBe(true);
130
- });
131
-
132
- it('should reject passwords with null characters', () => {
133
- const nullPassword = 'Pass123!\x00';
134
- // The schema may actually allow null bytes, so we just test it doesn't crash
135
- expect(() => securePasswordSchema.safeParse(nullPassword)).not.toThrow();
136
- });
137
-
138
- it('should handle passwords with maximum variety', () => {
139
- const complexPassword = 'Complex123!@#$%^&*()[]';
140
- expect(securePasswordSchema.safeParse(complexPassword).success).toBe(true);
141
- });
142
-
143
- it('should calculate strength for very long passwords', () => {
144
- const longPassword = 'A'.repeat(100) + '1!';
145
- const result = calculatePasswordStrength(longPassword);
146
-
147
- expect(result.score).toBeGreaterThan(50);
148
- expect(result.level).toBeDefined();
149
- });
150
-
151
- it('should detect sequential patterns', () => {
152
- const sequentialPassword = 'qwerty123!';
153
- const result = calculatePasswordStrength(sequentialPassword);
154
-
155
- expect(result.level).not.toBe('strong');
156
- });
157
-
158
- it('should recognize keyboard pattern passwords', () => {
159
- const keyboardPattern = 'asdfgh123!';
160
- const result = calculatePasswordStrength(keyboardPattern);
161
-
162
- // Should penalize sequential keyboard patterns
163
- expect(result.score).toBeLessThan(80);
164
- });
165
-
166
- it('should handle mixed case passwords correctly', () => {
167
- const mixedCasePassword = 'PaSsWoRd123!';
168
- expect(securePasswordSchema.safeParse(mixedCasePassword).success).toBe(true);
169
-
170
- const result = calculatePasswordStrength(mixedCasePassword);
171
- expect(result.score).toBeGreaterThan(40);
172
- });
173
-
174
- it('should handle passwords with repeat characters', () => {
175
- const repeatingPassword = 'Aaaa1111!';
176
- expect(securePasswordSchema.safeParse(repeatingPassword).success).toBe(true);
177
-
178
- const result = calculatePasswordStrength(repeatingPassword);
179
- expect(result.score).toBeLessThan(result.score + 50); // Should still score reasonably
180
- });
181
-
182
- it('should validate passwords with only required characters (minimum secure)', () => {
183
- // Minimum secure password: 8 chars with uppercase, lowercase, number, and special
184
- const minSecurePassword = 'A1!bcdef';
185
- expect(securePasswordSchema.safeParse(minSecurePassword).success).toBe(true);
186
- });
187
-
188
- it('should reject secure schema passwords missing each requirement', () => {
189
- // Test one requirement at a time to avoid confusion
190
- const result1 = securePasswordSchema.safeParse('PASSWORD!');
191
- expect(result1.success).toBe(false); // No lowercase
192
-
193
- const result2 = securePasswordSchema.safeParse('password1!');
194
- expect(result2.success).toBe(false); // No uppercase
195
-
196
- const result3 = securePasswordSchema.safeParse('Password!');
197
- expect(result3.success).toBe(false); // No number
198
-
199
- const result4 = securePasswordSchema.safeParse('Password1');
200
- expect(result4.success).toBe(false); // No special
201
- });
202
- });
203
- });