@jmruthers/pace-core 0.6.9 → 0.6.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1182) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +74 -2
  5. package/audit-tool/audits/03-architecture.cjs +220 -20
  6. package/audit-tool/audits/04-code-quality.cjs +95 -3
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +214 -25
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +3 -26
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +120 -8
  19. package/cursor-rules/06-security-rbac.mdc +126 -2
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/DataTable-EFYP2QLE.js +16 -0
  24. package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
  25. package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
  26. package/dist/api-BZR2CYXL.js +5 -0
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/assets/app-icons/admin_favicon.svg +462 -0
  29. package/dist/assets/app-icons/base_favicon.svg +85 -0
  30. package/dist/assets/app-icons/cake_favicon.svg +68 -0
  31. package/dist/assets/app-icons/core_favicon.svg +256 -0
  32. package/dist/assets/app-icons/gear_favicon.svg +91 -0
  33. package/dist/assets/app-icons/medi_favicon.svg +92 -0
  34. package/dist/assets/app-icons/mint_favicon.svg +83 -0
  35. package/dist/assets/app-icons/pace_favicon.svg +49 -0
  36. package/dist/assets/app-icons/pump_favicon.svg +68 -0
  37. package/dist/assets/app-icons/seed_favicon.svg +91 -0
  38. package/dist/assets/app-icons/team_favicon.svg +67 -0
  39. package/dist/assets/app-icons/trac_favicon.svg +112 -0
  40. package/dist/assets/app-icons/trip_favicon.svg +102 -0
  41. package/dist/audit-HI2DHUVU.js +4 -0
  42. package/dist/auth-JvdRVaud.d.ts +49 -0
  43. package/dist/chunk-2DL2WSOE.js +327 -0
  44. package/dist/chunk-2OEVOGGR.js +9598 -0
  45. package/dist/chunk-44CNXN4P.js +15 -0
  46. package/dist/chunk-4R3T5ENU.js +2943 -0
  47. package/dist/chunk-7A6IMHH2.js +2321 -0
  48. package/dist/chunk-BTHN5MKC.js +121 -0
  49. package/dist/chunk-CU2BU2MQ.js +2 -0
  50. package/dist/chunk-D6BMFMQZ.js +200 -0
  51. package/dist/chunk-DDMPHZ3D.js +58 -0
  52. package/dist/chunk-ENLXB7GP.js +721 -0
  53. package/dist/chunk-J2KQK6DG.js +2159 -0
  54. package/dist/chunk-KJXRL3XE.js +6434 -0
  55. package/dist/chunk-L5LFKKLJ.js +61 -0
  56. package/dist/chunk-PCSHBLPB.js +811 -0
  57. package/dist/chunk-QRYSEPHB.js +429 -0
  58. package/dist/chunk-RMLY6KB5.js +187 -0
  59. package/dist/chunk-SACF5YSM.js +31 -0
  60. package/dist/chunk-UZNAFKGW.js +125 -0
  61. package/dist/chunk-V7FTM2LU.js +1080 -0
  62. package/dist/chunk-WY6Y7KC3.js +264 -0
  63. package/dist/chunk-XOJME5T7.js +407 -0
  64. package/dist/chunk-XPFVT3GN.js +492 -0
  65. package/dist/chunk-YFTFFJIV.js +529 -0
  66. package/dist/chunk-YYTWKVHO.js +1334 -0
  67. package/dist/components.d.ts +12 -89
  68. package/dist/components.js +23 -55
  69. package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
  70. package/dist/eslint-rules/index.cjs +3 -0
  71. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  72. package/dist/eslint-rules/rules/05-styling.cjs +507 -0
  73. package/dist/eslint-rules/rules/06-security-rbac.cjs +84 -0
  74. package/dist/event-BfCox3N2.d.ts +265 -0
  75. package/dist/file-reference-DU1hcawx.d.ts +164 -0
  76. package/dist/functions-DH45k8ec.d.ts +208 -0
  77. package/dist/hooks.d.ts +28 -14
  78. package/dist/hooks.js +90 -56
  79. package/dist/icons/index.d.ts +1 -0
  80. package/dist/icons/index.js +1 -0
  81. package/dist/index.d.ts +392 -155
  82. package/dist/index.js +337 -347
  83. package/dist/pagination-BW1mqywp.d.ts +201 -0
  84. package/dist/papaparseLoader-WG2UXQ22.js +7 -0
  85. package/dist/providers.d.ts +29 -14
  86. package/dist/providers.js +7 -5
  87. package/dist/rbac/eslint-rules.js +2 -2
  88. package/dist/rbac/index.d.ts +180 -351
  89. package/dist/rbac/index.js +13 -11
  90. package/dist/theming/runtime.d.ts +28 -5
  91. package/dist/theming/runtime.js +2 -2
  92. package/dist/timezone-BTWWXKVY.d.ts +696 -0
  93. package/dist/types-BE2sEHKd.d.ts +55 -0
  94. package/dist/types-CvOPXWWZ.d.ts +111 -0
  95. package/dist/types-Dr8sNhER.d.ts +50 -0
  96. package/dist/types.d.ts +20 -13
  97. package/dist/types.js +1 -0
  98. package/dist/usePublicPageContext-B91dGYW1.d.ts +4367 -0
  99. package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
  100. package/dist/utils.d.ts +338 -156
  101. package/dist/utils.js +78 -60
  102. package/dist/validation-g5n0hDkh.d.ts +177 -0
  103. package/docs/api/modules.md +1226 -1094
  104. package/docs/api-reference/components.md +5 -5
  105. package/docs/api-reference/rpc-functions.md +12 -3
  106. package/docs/core-concepts/rbac-system.md +8 -0
  107. package/docs/getting-started/cursor-rules.md +17 -20
  108. package/docs/getting-started/dependencies.md +1 -1
  109. package/docs/getting-started/setup.md +235 -0
  110. package/docs/implementation-guides/authentication.md +27 -0
  111. package/docs/implementation-guides/data-tables.md +365 -10
  112. package/docs/migration/ApiResult-migration.md +25 -0
  113. package/docs/rbac/RBAC_CONTRACT.md +0 -12
  114. package/docs/rbac/api-reference.md +33 -31
  115. package/docs/standards/0-standards-overview.md +50 -15
  116. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  117. package/docs/standards/2-project-structure-standards.md +45 -90
  118. package/docs/standards/3-architecture-standards.md +41 -1
  119. package/docs/standards/4-code-quality-standards.md +26 -6
  120. package/docs/standards/5-styling-standards.md +35 -1
  121. package/docs/standards/6-security-rbac-standards.md +288 -7
  122. package/docs/standards/7-api-tech-stack-standards.md +116 -17
  123. package/docs/standards/8-testing-documentation-standards.md +31 -0
  124. package/docs/standards/9-operations-standards.md +19 -0
  125. package/docs/standards/README.md +20 -201
  126. package/docs/testing/README.md +10 -0
  127. package/docs/testing/test-setup-for-consumers.md +916 -0
  128. package/docs/troubleshooting/common-issues.md +17 -1
  129. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  130. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  131. package/eslint-config-pace-core.cjs +24 -0
  132. package/package.json +14 -20
  133. package/scripts/build-docs.js +180 -0
  134. package/scripts/setup.cjs +536 -0
  135. package/scripts/validate.cjs +480 -0
  136. package/src/__mocks__/lucide-react.ts +0 -2
  137. package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
  138. package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
  139. package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
  140. package/src/__tests__/helpers/test-providers.test.tsx +99 -0
  141. package/src/__tests__/helpers/test-providers.tsx +37 -39
  142. package/src/__tests__/helpers/test-utils.test.tsx +447 -0
  143. package/src/__tests__/helpers/timer-utils.test.ts +371 -0
  144. package/src/assets/app-icons/admin_favicon.svg +462 -0
  145. package/src/assets/app-icons/base_favicon.svg +85 -0
  146. package/src/assets/app-icons/cake_favicon.svg +68 -0
  147. package/src/assets/app-icons/core_favicon.svg +256 -0
  148. package/src/assets/app-icons/gear_favicon.svg +91 -0
  149. package/src/assets/app-icons/index.test.ts +304 -0
  150. package/src/assets/app-icons/index.ts +83 -0
  151. package/src/assets/app-icons/medi_favicon.svg +92 -0
  152. package/src/assets/app-icons/mint_favicon.svg +83 -0
  153. package/src/assets/app-icons/pace_favicon.svg +49 -0
  154. package/src/assets/app-icons/pump_favicon.svg +68 -0
  155. package/src/assets/app-icons/seed_favicon.svg +91 -0
  156. package/src/assets/app-icons/team_favicon.svg +67 -0
  157. package/src/assets/app-icons/trac_favicon.svg +112 -0
  158. package/src/assets/app-icons/trip_favicon.svg +102 -0
  159. package/src/components/AddressField/AddressField.test.tsx +379 -4
  160. package/src/components/AddressField/AddressField.tsx +239 -213
  161. package/src/components/AddressField/types.ts +2 -2
  162. package/src/components/Alert/Alert.test.tsx +35 -25
  163. package/src/components/Alert/Alert.tsx +8 -8
  164. package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
  165. package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
  166. package/src/components/Avatar/Avatar.test.tsx +11 -1
  167. package/src/components/Avatar/Avatar.tsx +3 -2
  168. package/src/components/Badge/Badge.test.tsx +11 -1
  169. package/src/components/Button/Button.test.tsx +13 -3
  170. package/src/components/Button/Button.tsx +1 -1
  171. package/src/components/Calendar/Calendar.test.tsx +523 -131
  172. package/src/components/Calendar/Calendar.tsx +107 -488
  173. package/src/components/Card/Card.test.tsx +384 -258
  174. package/src/components/Card/Card.tsx +19 -10
  175. package/src/components/Checkbox/Checkbox.test.tsx +58 -174
  176. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  177. package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
  178. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  179. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  180. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  181. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  182. package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
  183. package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
  184. package/src/components/DataTable/DataTable.export.test.tsx +705 -0
  185. package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
  186. package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
  187. package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
  188. package/src/components/DataTable/DataTable.test.tsx +787 -416
  189. package/src/components/DataTable/DataTable.tsx +14 -14
  190. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  191. package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
  192. package/src/components/DataTable/DataTableCore.test.tsx +970 -0
  193. package/src/components/DataTable/README.md +155 -0
  194. package/src/components/DataTable/TESTING.md +101 -0
  195. package/src/components/DataTable/a11y.basic.test.tsx +788 -0
  196. package/src/components/DataTable/components/DataTableCore.tsx +126 -894
  197. package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
  198. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -3
  199. package/src/components/DataTable/components/ImportModal.tsx +82 -408
  200. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  201. package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
  202. package/src/components/DataTable/context/DataTableContext.tsx +13 -13
  203. package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
  204. package/src/components/DataTable/core/ColumnFactory.ts +3 -3
  205. package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
  206. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
  207. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
  208. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
  209. package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
  210. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +15 -3
  211. package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
  212. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  213. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  214. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  215. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  216. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  217. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  218. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  219. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  220. package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
  221. package/src/components/DataTable/hooks/useDataTablePermissions.ts +81 -260
  222. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  223. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  224. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  225. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  226. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  227. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  228. package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
  229. package/src/components/DataTable/hooks/useDataTableState.ts +161 -114
  230. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  231. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  232. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  233. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  234. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  235. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  236. package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
  237. package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
  238. package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
  239. package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
  240. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  241. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  242. package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
  243. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +311 -271
  244. package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
  245. package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
  246. package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
  247. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +27 -4
  248. package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
  249. package/src/components/DataTable/hooks/useTableColumns.ts +15 -39
  250. package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
  251. package/src/components/DataTable/hooks/useTableHandlers.ts +13 -22
  252. package/src/components/DataTable/index.ts +28 -5
  253. package/src/components/DataTable/keyboard.test.tsx +734 -0
  254. package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
  255. package/src/components/DataTable/pagination.modes.test.tsx +728 -0
  256. package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
  257. package/src/components/DataTable/styles.test.ts +379 -0
  258. package/src/components/DataTable/styles.ts +0 -1
  259. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  260. package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
  261. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  262. package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
  263. package/src/components/DataTable/test-utils.ts +94 -0
  264. package/src/components/DataTable/types/actions.ts +71 -0
  265. package/src/components/DataTable/types/base.ts +39 -0
  266. package/src/components/DataTable/types/columns.ts +125 -0
  267. package/src/components/DataTable/types/export.ts +32 -0
  268. package/src/components/DataTable/types/features.ts +81 -0
  269. package/src/components/DataTable/types/hierarchical.ts +44 -0
  270. package/src/components/DataTable/types/index.ts +43 -0
  271. package/src/components/DataTable/types/pagination.ts +85 -0
  272. package/src/components/DataTable/types/performance.ts +47 -0
  273. package/src/components/DataTable/types/props.ts +62 -0
  274. package/src/components/DataTable/types/rbac.ts +45 -0
  275. package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
  276. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  277. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
  278. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
  279. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  280. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  281. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  282. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  283. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  284. package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
  285. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  286. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  287. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  288. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  289. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  290. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  291. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  292. package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
  293. package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
  294. package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
  295. package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
  296. package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
  297. package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
  298. package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
  299. package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
  300. package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
  301. package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
  302. package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
  303. package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
  304. package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
  305. package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
  306. package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
  307. package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
  308. package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
  309. package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
  310. package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
  311. package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
  312. package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
  313. package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
  314. package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
  315. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  316. package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
  317. package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
  318. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
  319. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
  320. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
  321. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
  322. package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
  323. package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
  324. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  325. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  326. package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
  327. package/src/components/DataTable/utils/a11yUtils.ts +1 -1
  328. package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
  329. package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
  330. package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
  331. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  332. package/src/components/DataTable/utils/csvParse.ts +65 -0
  333. package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
  334. package/src/components/DataTable/utils/errorHandling.ts +3 -1
  335. package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
  336. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  337. package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
  338. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  339. package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
  340. package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
  341. package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
  342. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  343. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  344. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  345. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  346. package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
  347. package/src/components/DataTable/utils/paginationUtils.ts +7 -4
  348. package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
  349. package/src/components/DataTable/utils/performanceUtils.ts +1 -1
  350. package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
  351. package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
  352. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -67
  353. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +18 -25
  354. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
  355. package/src/components/DateTimeField/DateTimeField.test.tsx +3 -16
  356. package/src/components/DateTimeField/DateTimeField.tsx +1 -1
  357. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  358. package/src/components/Dialog/Dialog.test.tsx +2865 -458
  359. package/src/components/Dialog/Dialog.tsx +183 -986
  360. package/src/components/Dialog/dialogLock.test.ts +238 -0
  361. package/src/components/Dialog/dialogLock.ts +98 -0
  362. package/src/components/Dialog/index.ts +2 -0
  363. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  364. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  365. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  366. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  367. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  368. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  369. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
  370. package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
  371. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
  372. package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
  373. package/src/components/ErrorBoundary/index.ts +3 -4
  374. package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
  375. package/src/components/FileDisplay/FileDisplay.test.tsx +479 -247
  376. package/src/components/FileDisplay/FileDisplay.tsx +29 -659
  377. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  378. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  379. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  380. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  381. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  382. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  383. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  384. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  385. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  386. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  387. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  388. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  389. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  390. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  391. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  392. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  393. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  394. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  395. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  396. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  397. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  398. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  399. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  400. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  401. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  402. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  403. package/src/components/FileDisplay/index.tsx +1 -1
  404. package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
  405. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  406. package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1438 -0
  407. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  408. package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
  409. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  410. package/src/components/FileUpload/FileUpload.test.tsx +69 -27
  411. package/src/components/FileUpload/FileUpload.tsx +112 -527
  412. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  413. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  414. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  415. package/src/components/FileUpload/index.tsx +1 -1
  416. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  417. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  418. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  419. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  420. package/src/components/Footer/Footer.test.tsx +15 -382
  421. package/src/components/Footer/Footer.tsx +8 -125
  422. package/src/components/Form/Form.test.tsx +425 -88
  423. package/src/components/Form/Form.tsx +91 -299
  424. package/src/components/Form/useFormPersistence.ts +257 -0
  425. package/src/components/Header/Header.test.tsx +653 -163
  426. package/src/components/Header/Header.tsx +62 -44
  427. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
  428. package/src/components/Input/Input.test.tsx +34 -120
  429. package/src/components/Input/Input.tsx +1 -1
  430. package/src/components/Label/Label.test.tsx +46 -45
  431. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +8 -11
  432. package/src/components/LoginForm/LoginForm.test.tsx +0 -1
  433. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  434. package/src/components/NavigationMenu/NavigationMenu.test.tsx +2422 -102
  435. package/src/components/NavigationMenu/NavigationMenu.tsx +62 -362
  436. package/src/components/NavigationMenu/index.ts +6 -1
  437. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  438. package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
  439. package/src/components/NavigationMenu/useNavigationFiltering.ts +199 -308
  440. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  441. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1322 -0
  442. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +50 -49
  443. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
  444. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +103 -85
  445. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +774 -44
  446. package/src/components/PaceAppLayout/PaceAppLayout.tsx +282 -764
  447. package/src/components/PaceAppLayout/README.md +0 -9
  448. package/src/components/PaceAppLayout/test-setup.tsx +15 -9
  449. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  450. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  451. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  452. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  453. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  454. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  455. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  456. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +782 -20
  457. package/src/components/PaceLoginPage/PaceLoginPage.tsx +33 -125
  458. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  459. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
  460. package/src/components/Progress/Progress.test.tsx +127 -1
  461. package/src/components/Progress/Progress.tsx +1 -2
  462. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
  463. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -217
  464. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  465. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  466. package/src/components/PublicLayout/PublicLayout.test.tsx +1640 -38
  467. package/src/components/PublicLayout/PublicPageContext.ts +28 -0
  468. package/src/components/PublicLayout/PublicPageLayout.tsx +134 -75
  469. package/src/components/PublicLayout/PublicPageProvider.tsx +7 -42
  470. package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
  471. package/src/components/Select/Select.test.tsx +45 -8
  472. package/src/components/Select/Select.tsx +57 -40
  473. package/src/components/Select/context.test.tsx +56 -0
  474. package/src/components/Select/text.test.tsx +104 -0
  475. package/src/components/Select/text.ts +26 -0
  476. package/src/components/Select/types.ts +3 -0
  477. package/src/components/Select/useSelectEvents.test.ts +279 -0
  478. package/src/components/Select/useSelectEvents.ts +87 -0
  479. package/src/components/Select/useSelectSearch.test.tsx +295 -0
  480. package/src/components/Select/useSelectSearch.ts +91 -0
  481. package/src/components/Select/useSelectState.test.ts +268 -0
  482. package/src/components/Select/useSelectState.ts +104 -0
  483. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
  484. package/src/components/Switch/Switch.test.tsx +57 -153
  485. package/src/components/Table/Table.test.tsx +395 -317
  486. package/src/components/Tabs/Tabs.test.tsx +270 -0
  487. package/src/components/Tabs/Tabs.tsx +4 -4
  488. package/src/components/Textarea/Textarea.test.tsx +11 -38
  489. package/src/components/Toast/Toast.test.tsx +425 -496
  490. package/src/components/Tooltip/Tooltip.test.tsx +4 -21
  491. package/src/components/UserMenu/UserMenu.test.tsx +1 -21
  492. package/src/components/UserMenu/UserMenu.tsx +0 -1
  493. package/src/components/index.test.ts +346 -0
  494. package/src/components/index.ts +12 -1
  495. package/src/constants/performance.test.ts +91 -0
  496. package/src/hooks/ServiceHooks.test.tsx +725 -0
  497. package/src/hooks/hooks.integration.test.tsx +608 -0
  498. package/src/hooks/index.ts +18 -3
  499. package/src/hooks/index.unit.test.ts +220 -0
  500. package/src/hooks/public/usePublicEvent.test.ts +304 -0
  501. package/src/hooks/public/usePublicEvent.ts +11 -11
  502. package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
  503. package/src/hooks/public/usePublicEventLogo.ts +2 -2
  504. package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
  505. package/src/hooks/public/usePublicRouteParams.ts +2 -2
  506. package/src/hooks/services/useAuth.ts +9 -7
  507. package/src/hooks/services/useAuthService.ts +1 -1
  508. package/src/hooks/services/useEventService.ts +1 -1
  509. package/src/hooks/useAccessibleApps.test.ts +400 -0
  510. package/src/hooks/useAccessibleApps.ts +264 -0
  511. package/src/hooks/useAddressAutocomplete.test.ts +170 -47
  512. package/src/hooks/useAddressAutocomplete.ts +109 -81
  513. package/src/hooks/useApiFetch.unit.test.ts +111 -0
  514. package/src/hooks/useAppConfig.ts +13 -3
  515. package/src/hooks/useAppConfig.unit.test.ts +712 -0
  516. package/src/hooks/useComponentPerformance.unit.test.tsx +314 -0
  517. package/src/hooks/useDataTablePerformance.ts +111 -130
  518. package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
  519. package/src/hooks/useDataTableState.test.ts +170 -0
  520. package/src/hooks/useDataTableState.ts +5 -5
  521. package/src/hooks/useDebounce.unit.test.ts +157 -0
  522. package/src/hooks/useEventTheme.test.ts +70 -18
  523. package/src/hooks/useEventTheme.ts +50 -22
  524. package/src/hooks/useEvents.ts +49 -2
  525. package/src/hooks/useEvents.unit.test.ts +227 -0
  526. package/src/hooks/useFileReference.test.ts +388 -107
  527. package/src/hooks/useFileReference.ts +184 -179
  528. package/src/hooks/useFileUrl.ts +1 -1
  529. package/src/hooks/useFileUrl.unit.test.ts +686 -0
  530. package/src/hooks/useFileUrlCache.test.ts +319 -0
  531. package/src/hooks/useFileUrlCache.ts +5 -2
  532. package/src/hooks/useFocusManagement.unit.test.ts +604 -0
  533. package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
  534. package/src/hooks/useFormDialog.test.ts +307 -0
  535. package/src/hooks/useFormDialog.ts +2 -2
  536. package/src/hooks/useInactivityTracker.ts +141 -134
  537. package/src/hooks/useInactivityTracker.unit.test.ts +446 -0
  538. package/src/hooks/useIsMobile.unit.test.ts +317 -0
  539. package/src/hooks/useIsPrint.ts +62 -0
  540. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  541. package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
  542. package/src/hooks/useOrganisationPermissions.test.ts +1 -2
  543. package/src/hooks/useOrganisationPermissions.ts +1 -4
  544. package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
  545. package/src/hooks/useOrganisationSecurity.test.ts +4 -33
  546. package/src/hooks/useOrganisationSecurity.ts +192 -203
  547. package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
  548. package/src/hooks/useOrganisations.ts +1 -1
  549. package/src/hooks/useOrganisations.unit.test.ts +369 -0
  550. package/src/hooks/usePerformanceMonitor.ts +1 -1
  551. package/src/hooks/usePerformanceMonitor.unit.test.ts +693 -0
  552. package/src/hooks/usePermissionCache.test.ts +298 -329
  553. package/src/hooks/usePermissionCache.ts +277 -276
  554. package/src/hooks/usePreventTabReload.test.ts +307 -0
  555. package/src/hooks/usePublicEvent.simple.test.ts +794 -0
  556. package/src/hooks/usePublicEvent.test.ts +670 -0
  557. package/src/hooks/usePublicEvent.unit.test.ts +638 -0
  558. package/src/hooks/usePublicFileDisplay.test.ts +948 -0
  559. package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
  560. package/src/hooks/useQueryCache.test.ts +391 -0
  561. package/src/hooks/useQueryCache.ts +7 -9
  562. package/src/hooks/useRBAC.unit.test.ts +253 -0
  563. package/src/hooks/useSessionDraft.test.ts +556 -0
  564. package/src/hooks/useSessionDraft.ts +14 -11
  565. package/src/hooks/useSessionRestoration.ts +1 -1
  566. package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
  567. package/src/hooks/useStorage.ts +94 -54
  568. package/src/hooks/useStorage.unit.test.ts +684 -0
  569. package/src/hooks/useToast.test.ts +413 -0
  570. package/src/hooks/useToast.ts +2 -2
  571. package/src/hooks/useToast.unit.test.tsx +481 -0
  572. package/src/hooks/useZodForm.ts +3 -3
  573. package/src/hooks/useZodForm.unit.test.tsx +191 -0
  574. package/src/icons/index.test.ts +133 -0
  575. package/src/icons/index.ts +3 -1
  576. package/src/index.test.ts +528 -0
  577. package/src/index.ts +56 -9
  578. package/src/providers/AuthProvider.test.tsx +218 -0
  579. package/src/providers/EventProvider.test.tsx +487 -0
  580. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  581. package/src/providers/InactivityProvider.test.tsx +421 -0
  582. package/src/providers/ProviderLifecycle.test.tsx +308 -0
  583. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
  584. package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
  585. package/src/providers/index.test.ts +138 -0
  586. package/src/providers/services/AuthServiceContext.ts +27 -0
  587. package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
  588. package/src/providers/services/AuthServiceProvider.test.tsx +638 -0
  589. package/src/providers/services/AuthServiceProvider.tsx +81 -20
  590. package/src/providers/services/EventServiceContext.ts +25 -0
  591. package/src/providers/services/EventServiceProvider.test.tsx +839 -0
  592. package/src/providers/services/EventServiceProvider.tsx +11 -20
  593. package/src/providers/services/InactivityServiceContext.ts +25 -0
  594. package/src/providers/services/InactivityServiceProvider.test.tsx +662 -0
  595. package/src/providers/services/InactivityServiceProvider.tsx +7 -17
  596. package/src/providers/services/OrganisationServiceContext.ts +25 -0
  597. package/src/providers/services/OrganisationServiceProvider.test.tsx +440 -0
  598. package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
  599. package/src/providers/services/UnifiedAuthContext.ts +102 -0
  600. package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
  601. package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
  602. package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
  603. package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
  604. package/src/providers/services/UnifiedAuthProvider.tsx +147 -497
  605. package/src/providers/services/contexts.test.tsx +281 -0
  606. package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
  607. package/src/providers/services/useUnifiedAuth.ts +29 -0
  608. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  609. package/src/providers/useInactivity.test-helper.ts +27 -0
  610. package/src/rbac/README.md +5 -5
  611. package/src/rbac/adapters.comprehensive.test.tsx +429 -0
  612. package/src/rbac/adapters.test.tsx +654 -0
  613. package/src/rbac/adapters.tsx +53 -38
  614. package/src/rbac/api.test.ts +986 -259
  615. package/src/rbac/api.ts +260 -216
  616. package/src/rbac/audit-batched.test.ts +550 -0
  617. package/src/rbac/audit-batched.ts +5 -4
  618. package/src/rbac/audit.test.ts +225 -28
  619. package/src/rbac/audit.ts +26 -18
  620. package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
  621. package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
  622. package/src/rbac/cache-invalidation.test.ts +715 -0
  623. package/src/rbac/cache-invalidation.ts +18 -15
  624. package/src/rbac/cache.test.ts +123 -63
  625. package/src/rbac/cache.ts +3 -4
  626. package/src/rbac/components/AccessDenied.test.tsx +324 -0
  627. package/src/rbac/components/AccessDenied.tsx +20 -18
  628. package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
  629. package/src/rbac/components/NavigationGuard.tsx +10 -8
  630. package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
  631. package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
  632. package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
  633. package/src/rbac/components/PagePermissionGuard.test.tsx +1430 -0
  634. package/src/rbac/components/PagePermissionGuard.tsx +188 -381
  635. package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
  636. package/src/rbac/config.test.ts +131 -48
  637. package/src/rbac/config.ts +69 -26
  638. package/src/rbac/docs/event-based-apps.md +26 -13
  639. package/src/rbac/engine.comprehensive.test.ts +808 -0
  640. package/src/rbac/engine.test.ts +974 -130
  641. package/src/rbac/engine.ts +53 -13
  642. package/src/rbac/errors.test.ts +99 -87
  643. package/src/rbac/errors.ts +89 -55
  644. package/src/rbac/eslint-rules.js +2 -2
  645. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  646. package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
  647. package/src/rbac/hooks/permissions/useAccessLevel.ts +23 -14
  648. package/src/rbac/hooks/permissions/useCan.test.ts +798 -0
  649. package/src/rbac/hooks/permissions/useCan.ts +173 -253
  650. package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
  651. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +63 -10
  652. package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
  653. package/src/rbac/hooks/permissions/usePermissions.ts +50 -78
  654. package/src/rbac/hooks/useCan.test.ts +348 -32
  655. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  656. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  657. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  658. package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
  659. package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
  660. package/src/rbac/hooks/usePermissions.test.ts +459 -33
  661. package/src/rbac/hooks/usePermissions.ts +5 -7
  662. package/src/rbac/hooks/useRBAC.test.ts +1784 -21
  663. package/src/rbac/hooks/useRBAC.ts +148 -88
  664. package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
  665. package/src/rbac/hooks/useResolvedScope.ts +4 -1
  666. package/src/rbac/hooks/useResourcePermissions.test.ts +561 -24
  667. package/src/rbac/hooks/useResourcePermissions.ts +76 -140
  668. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  669. package/src/rbac/hooks/useRoleManagement.test.ts +634 -61
  670. package/src/rbac/hooks/useRoleManagement.ts +158 -586
  671. package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
  672. package/src/rbac/hooks/useSecureSupabase.ts +21 -14
  673. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  674. package/src/rbac/index.test.ts +107 -0
  675. package/src/rbac/index.ts +32 -32
  676. package/src/rbac/performance.test.ts +451 -0
  677. package/src/rbac/permissions.test.ts +149 -68
  678. package/src/rbac/permissions.ts +0 -3
  679. package/src/rbac/rbac-core.test.tsx +276 -0
  680. package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
  681. package/src/rbac/rbac-engine-simplified.test.ts +252 -0
  682. package/src/rbac/rbac-functions.test.ts +703 -0
  683. package/src/rbac/rbac-integration.test.ts +523 -0
  684. package/src/rbac/rbac-role-isolation.test.ts +456 -0
  685. package/src/rbac/request-deduplication.test.ts +352 -0
  686. package/src/rbac/request-deduplication.ts +5 -4
  687. package/src/rbac/scenarios.user-role.test.tsx +271 -0
  688. package/src/rbac/secureClient.test.ts +499 -115
  689. package/src/rbac/secureClient.ts +54 -28
  690. package/src/rbac/security.test.ts +448 -44
  691. package/src/rbac/security.ts +7 -6
  692. package/src/rbac/types/roleManagement.ts +66 -0
  693. package/src/rbac/types.test.ts +236 -0
  694. package/src/rbac/types.ts +7 -5
  695. package/src/rbac/utils/clientSecurity.test.ts +192 -0
  696. package/src/rbac/utils/clientSecurity.ts +6 -4
  697. package/src/rbac/utils/contextValidator.test.ts +126 -0
  698. package/src/rbac/utils/contextValidator.ts +6 -3
  699. package/src/rbac/utils/deep-equal.test.ts +76 -0
  700. package/src/rbac/utils/eventContext.test.ts +401 -0
  701. package/src/rbac/utils/eventContext.ts +38 -34
  702. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  703. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  704. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  705. package/src/services/AuthService.edge-cases.test.ts +746 -0
  706. package/src/services/AuthService.restoreSession.test.ts +59 -0
  707. package/src/services/AuthService.test.ts +1362 -0
  708. package/src/services/AuthService.ts +197 -216
  709. package/src/services/BaseService.edge-cases.test.ts +506 -0
  710. package/src/services/BaseService.test.ts +363 -0
  711. package/src/services/EventService.edge-cases.test.ts +636 -0
  712. package/src/services/EventService.eventColours.test.ts +64 -0
  713. package/src/services/EventService.test.ts +1250 -0
  714. package/src/services/EventService.ts +244 -315
  715. package/src/services/InactivityService.edge-cases.test.ts +492 -0
  716. package/src/services/InactivityService.lifecycle.test.ts +406 -0
  717. package/src/services/InactivityService.test.ts +829 -0
  718. package/src/services/InactivityService.ts +172 -213
  719. package/src/services/OrganisationService.edge-cases.test.ts +633 -0
  720. package/src/services/OrganisationService.pagination.test.ts +409 -0
  721. package/src/services/OrganisationService.test.ts +1579 -0
  722. package/src/services/OrganisationService.ts +186 -257
  723. package/src/services/base/BaseService.test.ts +214 -0
  724. package/src/services/interfaces/IAuthService.test.ts +184 -0
  725. package/src/services/interfaces/IAuthService.ts +10 -9
  726. package/src/services/interfaces/IEventService.test.ts +176 -0
  727. package/src/services/interfaces/IInactivityService.test.ts +183 -0
  728. package/src/services/interfaces/IOrganisationService.test.ts +207 -0
  729. package/src/services/interfaces/IOrganisationService.ts +0 -1
  730. package/src/styles/core.css +244 -12
  731. package/src/theming/parseEventColours.test.ts +321 -0
  732. package/src/theming/parseEventColours.ts +18 -9
  733. package/src/theming/runtime.test.ts +495 -0
  734. package/src/theming/runtime.ts +72 -7
  735. package/src/types/api-result.ts +53 -0
  736. package/src/types/auth.ts +0 -1
  737. package/src/types/core.test.ts +397 -0
  738. package/src/types/database-generated.test.ts +78 -0
  739. package/src/types/database.generated.ts +45 -10
  740. package/src/types/event.ts +39 -19
  741. package/src/types/file-reference.test.ts +351 -0
  742. package/src/types/file-reference.ts +37 -12
  743. package/src/types/guards.test.ts +246 -0
  744. package/src/types/index.test.ts +265 -0
  745. package/src/types/index.ts +3 -0
  746. package/src/types/organisation.roles.test.ts +55 -0
  747. package/src/types/organisation.test.ts +1105 -0
  748. package/src/types/organisation.ts +15 -15
  749. package/src/types/rpc-responses.ts +33 -0
  750. package/src/types/supabase.ts +14 -6
  751. package/src/types/theme.test.ts +830 -0
  752. package/src/types/type-validation.test.ts +526 -0
  753. package/src/types/validation.test.ts +729 -0
  754. package/src/types/vitest-globals.d.ts +1 -1
  755. package/src/utils/app/appConfig.test.ts +235 -0
  756. package/src/utils/app/appIdResolver.test.ts +252 -57
  757. package/src/utils/app/appIdResolver.ts +31 -20
  758. package/src/utils/app/appNameResolver.test.ts +18 -10
  759. package/src/utils/app/appNameResolver.ts +11 -9
  760. package/src/utils/app/appPortMap.test.ts +125 -0
  761. package/src/utils/app/appPortMap.ts +51 -0
  762. package/src/utils/app/buildAppUrl.test.ts +273 -0
  763. package/src/utils/app/buildAppUrl.ts +114 -0
  764. package/src/utils/appConfig.unit.test.ts +55 -0
  765. package/src/utils/audit/audit.test.ts +354 -39
  766. package/src/utils/audit.unit.test.ts +69 -0
  767. package/src/utils/auth-utils.unit.test.ts +69 -0
  768. package/src/utils/bundleAnalysis.unit.test.ts +326 -0
  769. package/src/utils/cn.unit.test.ts +34 -0
  770. package/src/utils/context/organisationContext.test.ts +115 -95
  771. package/src/utils/context/organisationContext.ts +32 -43
  772. package/src/utils/context/sessionTracking.test.ts +354 -0
  773. package/src/utils/core/cn.test.ts +66 -0
  774. package/src/utils/core/debugLogger.test.ts +113 -0
  775. package/src/utils/core/debugLogger.ts +15 -8
  776. package/src/utils/core/logger.test.ts +217 -0
  777. package/src/utils/core/logger.ts +20 -16
  778. package/src/utils/core/mergeRefs.ts +24 -0
  779. package/src/utils/debugLogger.test.ts +417 -0
  780. package/src/utils/device/deviceFingerprint.test.ts +8 -5
  781. package/src/utils/device/deviceFingerprint.ts +3 -3
  782. package/src/utils/deviceFingerprint.unit.test.ts +818 -0
  783. package/src/utils/dynamic/createLazyComponent.tsx +46 -0
  784. package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
  785. package/src/utils/dynamic/dynamicUtils.ts +6 -6
  786. package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
  787. package/src/utils/dynamic/lazyLoad.tsx +8 -36
  788. package/src/utils/dynamic/papaparseLoader.ts +7 -0
  789. package/src/utils/dynamicUtils.unit.test.ts +331 -0
  790. package/src/utils/file-reference/file-reference.test.ts +1238 -0
  791. package/src/utils/file-reference/index.ts +330 -348
  792. package/src/utils/formatDate.unit.test.ts +109 -0
  793. package/src/utils/formatting/formatDate.test.ts +22 -148
  794. package/src/utils/formatting/formatDateTime.test.ts +41 -119
  795. package/src/utils/formatting/formatDateTimeTimezone.test.ts +41 -85
  796. package/src/utils/formatting/formatNumber.test.ts +259 -0
  797. package/src/utils/formatting/formatTime.test.ts +36 -128
  798. package/src/utils/formatting/formatting.ts +1 -1
  799. package/src/utils/formatting.unit.test.ts +99 -0
  800. package/src/utils/google-places/googlePlacesUtils.test.ts +127 -36
  801. package/src/utils/google-places/googlePlacesUtils.ts +67 -86
  802. package/src/utils/google-places/loadGoogleMapsScript.test.ts +68 -8
  803. package/src/utils/google-places/loadGoogleMapsScript.ts +140 -118
  804. package/src/utils/index.ts +52 -11
  805. package/src/utils/index.unit.test.ts +251 -0
  806. package/src/utils/lazyLoad.unit.test.tsx +319 -0
  807. package/src/utils/location/location.test.ts +19 -116
  808. package/src/utils/logger.unit.test.ts +398 -0
  809. package/src/utils/organisationContext.unit.test.ts +180 -0
  810. package/src/utils/performance/bundleAnalysis.test.ts +148 -0
  811. package/src/utils/performance/bundleAnalysis.ts +16 -22
  812. package/src/utils/performance/performanceBenchmark.test.ts +251 -0
  813. package/src/utils/performance/performanceBenchmark.ts +12 -4
  814. package/src/utils/performance/performanceBudgets.test.ts +241 -0
  815. package/src/utils/performance/performanceBudgets.ts +9 -6
  816. package/src/utils/performanceBenchmark.test.ts +174 -0
  817. package/src/utils/performanceBudgets.unit.test.ts +288 -0
  818. package/src/utils/permissionTypes.unit.test.ts +250 -0
  819. package/src/utils/permissionUtils.unit.test.ts +362 -0
  820. package/src/utils/permissions/permissionTypes.test.ts +149 -0
  821. package/src/utils/permissions/permissionUtils.test.ts +20 -42
  822. package/src/utils/persistence/keyDerivation.test.ts +306 -0
  823. package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
  824. package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
  825. package/src/utils/request-deduplication.test.ts +349 -0
  826. package/src/utils/request-deduplication.ts +6 -4
  827. package/src/utils/sanitization.unit.test.ts +346 -0
  828. package/src/utils/schemaUtils.unit.test.ts +441 -0
  829. package/src/utils/secureDataAccess.unit.test.ts +334 -0
  830. package/src/utils/secureErrors.unit.test.ts +390 -0
  831. package/src/utils/secureStorage.unit.test.ts +289 -0
  832. package/src/utils/security/auth-utils.ts +38 -27
  833. package/src/utils/security/secureDataAccess.test.ts +22 -191
  834. package/src/utils/security/secureDataAccess.ts +241 -281
  835. package/src/utils/security/secureErrors.test.ts +163 -0
  836. package/src/utils/security/secureStorage.test.ts +156 -0
  837. package/src/utils/security/secureStorage.ts +1 -1
  838. package/src/utils/security/security.test.ts +212 -0
  839. package/src/utils/security/security.ts +15 -18
  840. package/src/utils/security/securityMonitor.test.ts +90 -0
  841. package/src/utils/security/securityMonitor.ts +1 -1
  842. package/src/utils/security.unit.test.ts +155 -0
  843. package/src/utils/securityMonitor.unit.test.ts +276 -0
  844. package/src/utils/sessionTracking.unit.test.ts +218 -0
  845. package/src/utils/storage/config.unit.test.ts +239 -0
  846. package/src/utils/storage/helpers.test.ts +769 -456
  847. package/src/utils/storage/helpers.ts +174 -253
  848. package/src/utils/storage/index.unit.test.ts +68 -0
  849. package/src/utils/storage/storageUtils.ts +32 -0
  850. package/src/utils/storage/types.ts +9 -2
  851. package/src/utils/supabase/createBaseClient.test.ts +201 -0
  852. package/src/utils/supabase/createBaseClient.ts +2 -1
  853. package/src/utils/timezone/timezone.test.ts +26 -44
  854. package/src/utils/timezone.test.ts +345 -0
  855. package/src/utils/validation/common.test.ts +115 -0
  856. package/src/utils/validation/csrf.test.ts +198 -0
  857. package/src/utils/validation/csrf.ts +42 -41
  858. package/src/utils/validation/htmlSanitization.ts +27 -31
  859. package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
  860. package/src/utils/validation/passwordSchema.test.ts +164 -0
  861. package/src/utils/validation/schema.test.ts +127 -0
  862. package/src/utils/validation/schema.ts +6 -3
  863. package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
  864. package/src/utils/validation/sqlInjectionProtection.ts +2 -2
  865. package/src/utils/validation/user.test.ts +173 -0
  866. package/src/utils/validation/validation.test.ts +197 -0
  867. package/src/utils/validation/validationUtils.test.ts +294 -0
  868. package/src/utils/validation.unit.test.ts +307 -0
  869. package/src/utils/validationUtils.unit.test.ts +558 -0
  870. package/src/vite-env.d.ts +6 -0
  871. package/dist/AuthService-DmfO5rGS.d.ts +0 -524
  872. package/dist/DataTable-DRUIgtUH.d.ts +0 -166
  873. package/dist/DataTable-SOAFXIWY.js +0 -15
  874. package/dist/PublicPageProvider-CIGSujI2.d.ts +0 -4147
  875. package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
  876. package/dist/UnifiedAuthProvider-CKvHP1MK.d.ts +0 -139
  877. package/dist/api-7P7DI652.js +0 -4
  878. package/dist/audit-MYQXYZFU.js +0 -3
  879. package/dist/auth-BZOJqrdd.d.ts +0 -49
  880. package/dist/chunk-4DDCYDQ3.js +0 -544
  881. package/dist/chunk-5HNSDQWH.js +0 -5046
  882. package/dist/chunk-5W2A3DRC.js +0 -164
  883. package/dist/chunk-6GLLNA6U.js +0 -31
  884. package/dist/chunk-7ILTDCL2.js +0 -80
  885. package/dist/chunk-A3W6LW53.js +0 -70
  886. package/dist/chunk-AHU7G2R5.js +0 -423
  887. package/dist/chunk-C7ZQ5O4C.js +0 -481
  888. package/dist/chunk-EF2UGZWY.js +0 -611
  889. package/dist/chunk-FEJLJNWA.js +0 -181
  890. package/dist/chunk-FYHN4DD5.js +0 -415
  891. package/dist/chunk-GS5672WG.js +0 -2003
  892. package/dist/chunk-HF6O3O37.js +0 -187
  893. package/dist/chunk-J2U36LHD.js +0 -8517
  894. package/dist/chunk-LX6U42O3.js +0 -2177
  895. package/dist/chunk-MPBLMWVR.js +0 -2161
  896. package/dist/chunk-OJ4SKRSV.js +0 -105
  897. package/dist/chunk-S6ZQKDY6.js +0 -62
  898. package/dist/chunk-S7DKJPLT.js +0 -699
  899. package/dist/chunk-T5CVK4R3.js +0 -2816
  900. package/dist/chunk-TTRFSOKR.js +0 -121
  901. package/dist/chunk-Z2FNRKF3.js +0 -994
  902. package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
  903. package/dist/event-CW5YB_2p.d.ts +0 -239
  904. package/dist/file-reference-BavO2eQj.d.ts +0 -148
  905. package/dist/functions-lBy5L2ry.d.ts +0 -208
  906. package/dist/timezone-0AyangqX.d.ts +0 -697
  907. package/dist/types-BeoeWV5I.d.ts +0 -110
  908. package/dist/types-DXstZpNI.d.ts +0 -614
  909. package/dist/types-t9H8qKRw.d.ts +0 -55
  910. package/dist/usePublicRouteParams-DQLrDqDb.d.ts +0 -876
  911. package/dist/useToast-AyaT-x7p.d.ts +0 -68
  912. package/dist/validation-643vUDZW.d.ts +0 -177
  913. package/scripts/build-docs-incremental.js +0 -179
  914. package/scripts/eslint-audit.cjs +0 -123
  915. package/scripts/generate-docs.js +0 -157
  916. package/scripts/install-cursor-rules.cjs +0 -255
  917. package/scripts/install-eslint-config.cjs +0 -349
  918. package/scripts/setup-build-cache.js +0 -73
  919. package/scripts/validate-pre-publish.js +0 -145
  920. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
  921. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
  922. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
  923. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
  924. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -448
  925. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
  926. package/src/__tests__/hooks/usePermissions.test.ts +0 -268
  927. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  928. package/src/__tests__/public-recipe-view.test.ts +0 -228
  929. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -220
  930. package/src/__tests__/rls-policies.test.ts +0 -471
  931. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
  932. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
  933. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
  934. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
  935. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
  936. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -483
  937. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  938. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
  939. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -1474
  940. package/src/components/DataTable/__tests__/README.md +0 -145
  941. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
  942. package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
  943. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
  944. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -730
  945. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -325
  946. package/src/components/DataTable/__tests__/styles.test.ts +0 -382
  947. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
  948. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -380
  949. package/src/components/DataTable/__tests__/test-utils.ts +0 -94
  950. package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
  951. package/src/components/DataTable/components/ActionButtons.tsx +0 -190
  952. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
  953. package/src/components/DataTable/components/ColumnFilter.tsx +0 -118
  954. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
  955. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
  956. package/src/components/DataTable/components/DataTableLayout.tsx +0 -573
  957. package/src/components/DataTable/components/DataTableModals.tsx +0 -245
  958. package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
  959. package/src/components/DataTable/components/EditFields.tsx +0 -327
  960. package/src/components/DataTable/components/EditableRow.tsx +0 -462
  961. package/src/components/DataTable/components/EmptyState.tsx +0 -79
  962. package/src/components/DataTable/components/FilterRow.tsx +0 -141
  963. package/src/components/DataTable/components/LoadingState.tsx +0 -17
  964. package/src/components/DataTable/components/PaginationControls.tsx +0 -289
  965. package/src/components/DataTable/components/RowComponent.tsx +0 -403
  966. package/src/components/DataTable/components/SortIndicator.tsx +0 -50
  967. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -355
  968. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -657
  969. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -913
  970. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -572
  971. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -612
  972. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -708
  973. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -479
  974. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -475
  975. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -157
  976. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -1061
  977. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -437
  978. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -474
  979. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -617
  980. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -1093
  981. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -139
  982. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -519
  983. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -1004
  984. package/src/components/DataTable/components/cellValueUtils.ts +0 -40
  985. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
  986. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
  987. package/src/components/DataTable/components/index.ts +0 -16
  988. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -342
  989. package/src/components/DataTable/core/ActionManager.ts +0 -235
  990. package/src/components/DataTable/core/ColumnManager.ts +0 -205
  991. package/src/components/DataTable/core/DataManager.ts +0 -188
  992. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  993. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  994. package/src/components/DataTable/core/StateManager.ts +0 -312
  995. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -123
  996. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -305
  997. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -84
  998. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -115
  999. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -100
  1000. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -120
  1001. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -104
  1002. package/src/components/DataTable/core/index.ts +0 -1
  1003. package/src/components/DataTable/core/interfaces.ts +0 -338
  1004. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -521
  1005. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -167
  1006. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -124
  1007. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -117
  1008. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -102
  1009. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -596
  1010. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -53
  1011. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -214
  1012. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -448
  1013. package/src/components/DataTable/hooks/index.ts +0 -13
  1014. package/src/components/DataTable/types.ts +0 -761
  1015. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -612
  1016. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
  1017. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -266
  1018. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
  1019. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
  1020. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -247
  1021. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -570
  1022. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
  1023. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -251
  1024. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -207
  1025. package/src/components/DataTable/utils/index.ts +0 -10
  1026. package/src/components/PublicLayout/index.ts +0 -32
  1027. package/src/components/Select/hooks/useSelectEvents.ts +0 -87
  1028. package/src/components/Select/hooks/useSelectSearch.ts +0 -91
  1029. package/src/components/Select/hooks/useSelectState.ts +0 -104
  1030. package/src/components/Select/utils/text.ts +0 -26
  1031. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -615
  1032. package/src/hooks/__tests__/hooks.integration.test.tsx +0 -607
  1033. package/src/hooks/__tests__/index.unit.test.ts +0 -220
  1034. package/src/hooks/__tests__/useApiFetch.unit.test.ts +0 -111
  1035. package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -347
  1036. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -144
  1037. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -776
  1038. package/src/hooks/__tests__/useDataTableState.test.ts +0 -76
  1039. package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -82
  1040. package/src/hooks/__tests__/useEvents.unit.test.ts +0 -252
  1041. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1112
  1042. package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -916
  1043. package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -129
  1044. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -230
  1045. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -828
  1046. package/src/hooks/__tests__/useFormDialog.test.ts +0 -478
  1047. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
  1048. package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
  1049. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -910
  1050. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -294
  1051. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
  1052. package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
  1053. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
  1054. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  1055. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  1056. package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -88
  1057. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -785
  1058. package/src/hooks/__tests__/usePublicEvent.test.ts +0 -678
  1059. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -630
  1060. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -951
  1061. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -443
  1062. package/src/hooks/__tests__/useQueryCache.test.ts +0 -144
  1063. package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
  1064. package/src/hooks/__tests__/useSessionDraft.test.ts +0 -163
  1065. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
  1066. package/src/hooks/__tests__/useStorage.unit.test.ts +0 -751
  1067. package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
  1068. package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -37
  1069. package/src/hooks/public/index.ts +0 -36
  1070. package/src/hooks/public/usePublicFileDisplay.ts +0 -504
  1071. package/src/hooks/useFileDisplay.ts +0 -715
  1072. package/src/providers/OrganisationProvider.tsx +0 -92
  1073. package/src/providers/__tests__/AuthProvider.test.tsx +0 -287
  1074. package/src/providers/__tests__/EventProvider.test.tsx +0 -551
  1075. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  1076. package/src/providers/__tests__/InactivityProvider.test.tsx +0 -572
  1077. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -617
  1078. package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -424
  1079. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -596
  1080. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -263
  1081. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -294
  1082. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -434
  1083. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -313
  1084. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -486
  1085. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -399
  1086. package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -813
  1087. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
  1088. package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
  1089. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -392
  1090. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -258
  1091. package/src/rbac/__tests__/rbac-functions.test.ts +0 -647
  1092. package/src/rbac/__tests__/rbac-integration.test.ts +0 -524
  1093. package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
  1094. package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -282
  1095. package/src/rbac/audit-enhanced.ts +0 -384
  1096. package/src/rbac/compliance/database-validator.ts +0 -165
  1097. package/src/rbac/compliance/index.ts +0 -48
  1098. package/src/rbac/compliance/pattern-detector.ts +0 -553
  1099. package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
  1100. package/src/rbac/compliance/runtime-compliance.ts +0 -99
  1101. package/src/rbac/compliance/setup-validator.ts +0 -131
  1102. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -975
  1103. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -248
  1104. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -242
  1105. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1107
  1106. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -184
  1107. package/src/rbac/components/index.ts +0 -26
  1108. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -432
  1109. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -579
  1110. package/src/rbac/hooks/index.ts +0 -34
  1111. package/src/rbac/hooks/permissions/index.ts +0 -4
  1112. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  1113. package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -128
  1114. package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -53
  1115. package/src/rbac/utils/__tests__/eventContext.test.ts +0 -433
  1116. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
  1117. package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -39
  1118. package/src/services/__tests__/AuthService.test.ts +0 -1332
  1119. package/src/services/__tests__/BaseService.test.ts +0 -314
  1120. package/src/services/__tests__/EventService.eventColours.test.ts +0 -76
  1121. package/src/services/__tests__/EventService.test.ts +0 -1025
  1122. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -411
  1123. package/src/services/__tests__/InactivityService.test.ts +0 -654
  1124. package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
  1125. package/src/services/__tests__/OrganisationService.test.ts +0 -1176
  1126. package/src/theming/__tests__/parseEventColours.test.ts +0 -321
  1127. package/src/theming/__tests__/runtime.test.ts +0 -569
  1128. package/src/types/__tests__/file-reference.test.ts +0 -447
  1129. package/src/types/__tests__/guards.test.ts +0 -246
  1130. package/src/types/__tests__/organisation.roles.test.ts +0 -55
  1131. package/src/types/__tests__/organisation.test.ts +0 -1133
  1132. package/src/types/__tests__/theme.test.ts +0 -830
  1133. package/src/types/__tests__/type-validation.test.ts +0 -526
  1134. package/src/types/__tests__/validation.test.ts +0 -731
  1135. package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
  1136. package/src/utils/__tests__/audit.unit.test.ts +0 -69
  1137. package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
  1138. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -339
  1139. package/src/utils/__tests__/cn.unit.test.ts +0 -34
  1140. package/src/utils/__tests__/debugLogger.test.ts +0 -417
  1141. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
  1142. package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -318
  1143. package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
  1144. package/src/utils/__tests__/formatting.unit.test.ts +0 -99
  1145. package/src/utils/__tests__/index.unit.test.ts +0 -251
  1146. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -321
  1147. package/src/utils/__tests__/logger.unit.test.ts +0 -398
  1148. package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
  1149. package/src/utils/__tests__/performanceBenchmark.test.ts +0 -175
  1150. package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -253
  1151. package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
  1152. package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
  1153. package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
  1154. package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
  1155. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -335
  1156. package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
  1157. package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
  1158. package/src/utils/__tests__/security.unit.test.ts +0 -149
  1159. package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
  1160. package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
  1161. package/src/utils/__tests__/timezone.test.ts +0 -345
  1162. package/src/utils/__tests__/validation.unit.test.ts +0 -308
  1163. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
  1164. package/src/utils/app/appNameResolver.simple.test.ts +0 -212
  1165. package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -875
  1166. package/src/utils/google-places/index.ts +0 -26
  1167. package/src/utils/location/index.ts +0 -16
  1168. package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -135
  1169. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -123
  1170. package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
  1171. package/src/utils/storage/__tests__/index.unit.test.ts +0 -16
  1172. package/src/utils/storage/index.ts +0 -67
  1173. package/src/utils/timezone/index.ts +0 -17
  1174. package/src/utils/validation/__tests__/csrf.test.ts +0 -105
  1175. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -598
  1176. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -92
  1177. package/src/utils/validation/__tests__/validationUtils.test.ts +0 -72
  1178. package/src/utils/validation/index.ts +0 -73
  1179. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  1180. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  1181. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  1182. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -0,0 +1,1362 @@
1
+ /**
2
+ * @file AuthService Unit Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module Services
5
+ * @since 0.1.0
6
+ *
7
+ * Unit tests for AuthService class.
8
+ * Tests authentication operations, state management, and error handling.
9
+ */
10
+
11
+ import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest';
12
+ import { AuthService } from './AuthService';
13
+ import { AuthError } from '@supabase/supabase-js';
14
+
15
+ // Don't mock the logger - it now works in test mode
16
+ // We'll spy on the Logger class methods in beforeEach to verify calls
17
+ import { Logger } from '../utils/core/logger';
18
+
19
+ let mockLoggerFunctions: {
20
+ debug: ReturnType<typeof vi.spyOn>;
21
+ error: ReturnType<typeof vi.spyOn>;
22
+ warn: ReturnType<typeof vi.spyOn>;
23
+ info: ReturnType<typeof vi.spyOn>;
24
+ };
25
+
26
+ // Mock Supabase client
27
+ const createMockSupabaseClient = () => ({
28
+ auth: {
29
+ signInWithPassword: vi.fn(),
30
+ signUp: vi.fn(),
31
+ signOut: vi.fn(),
32
+ resetPasswordForEmail: vi.fn(),
33
+ updateUser: vi.fn(),
34
+ refreshSession: vi.fn(),
35
+ getSession: vi.fn(),
36
+ getUser: vi.fn(),
37
+ onAuthStateChange: vi.fn(),
38
+ },
39
+ });
40
+
41
+ describe('AuthService', () => {
42
+ let mockSupabase: ReturnType<typeof createMockSupabaseClient>;
43
+ let authService: AuthService;
44
+
45
+ beforeEach(() => {
46
+ // Spy on Logger methods to verify calls (logger now works in test mode)
47
+ mockLoggerFunctions = {
48
+ debug: vi.spyOn(Logger, 'debug'),
49
+ error: vi.spyOn(Logger, 'error'),
50
+ warn: vi.spyOn(Logger, 'warn'),
51
+ info: vi.spyOn(Logger, 'info'),
52
+ };
53
+
54
+ mockSupabase = createMockSupabaseClient();
55
+ authService = new AuthService(mockSupabase as any);
56
+ });
57
+
58
+ afterEach(() => {
59
+ authService.cleanup();
60
+ // Restore spies
61
+ mockLoggerFunctions.debug.mockRestore();
62
+ mockLoggerFunctions.error.mockRestore();
63
+ mockLoggerFunctions.warn.mockRestore();
64
+ mockLoggerFunctions.info.mockRestore();
65
+ vi.clearAllMocks();
66
+ });
67
+
68
+ describe('Initialization', () => {
69
+ it('should initialize with default state', () => {
70
+ expect(authService.getUser()).toBeNull();
71
+ expect(authService.getSession()).toBeNull();
72
+ expect(authService.isAuthenticated()).toBe(false);
73
+ expect(authService.isLoading()).toBe(false);
74
+ expect(authService.getError()).toBeNull();
75
+ });
76
+
77
+ it('should initialize service when created', async () => {
78
+ mockSupabase.auth.getSession.mockResolvedValue({
79
+ data: { session: null },
80
+ error: null
81
+ });
82
+ mockSupabase.auth.getUser.mockResolvedValue({
83
+ data: { user: null },
84
+ error: null
85
+ });
86
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
87
+ data: { subscription: { unsubscribe: vi.fn() } }
88
+ });
89
+
90
+ await authService.initialize();
91
+
92
+ expect(mockSupabase.auth.getSession).toHaveBeenCalled();
93
+ expect(mockSupabase.auth.onAuthStateChange).toHaveBeenCalled();
94
+ });
95
+ });
96
+
97
+ describe('Sign In', () => {
98
+ it('should sign in user successfully', async () => {
99
+ const mockUser = { id: '1', email: 'test@example.com' };
100
+ const mockSession = { access_token: 'token', user: mockUser };
101
+
102
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
103
+ data: { user: mockUser, session: mockSession },
104
+ error: null
105
+ });
106
+
107
+ const result = await authService.signIn('test@example.com', 'password');
108
+
109
+ expect(result.ok).toBe(true);
110
+ expect(result.data?.user).toEqual(mockUser);
111
+ expect(result.data?.session).toEqual(mockSession);
112
+ expect(authService.getUser()).toEqual(mockUser);
113
+ expect(authService.getSession()).toEqual(mockSession);
114
+ expect(authService.isAuthenticated()).toBe(true);
115
+ });
116
+
117
+ it('should handle sign in errors', async () => {
118
+ const mockError = new AuthError('Invalid credentials');
119
+
120
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
121
+ data: { user: null, session: null },
122
+ error: mockError
123
+ });
124
+
125
+ const result = await authService.signIn('test@example.com', 'wrongpassword');
126
+
127
+ expect(result.ok).toBe(false);
128
+ expect(result.error).toMatchObject({ message: mockError.message });
129
+ expect(authService.getError()).toEqual(mockError);
130
+ expect(authService.isAuthenticated()).toBe(false);
131
+ });
132
+
133
+ it('should handle missing Supabase client', async () => {
134
+ const serviceWithoutClient = new AuthService(null as any);
135
+
136
+ const result = await serviceWithoutClient.signIn('test@example.com', 'password');
137
+
138
+ expect(result.ok).toBe(false);
139
+ expect(result.error.message).toBe('Supabase client not available');
140
+ });
141
+ });
142
+
143
+ describe('Sign Up', () => {
144
+ it('should sign up user successfully', async () => {
145
+ const mockUser = { id: '1', email: 'test@example.com' };
146
+ const mockSession = { access_token: 'token', user: mockUser };
147
+
148
+ mockSupabase.auth.signUp.mockResolvedValue({
149
+ data: { user: mockUser, session: mockSession },
150
+ error: null
151
+ });
152
+
153
+ const result = await authService.signUp('test@example.com', 'password');
154
+
155
+ expect(result.ok).toBe(true);
156
+ expect(result.data?.user).toEqual(mockUser);
157
+ expect(result.data?.session).toEqual(mockSession);
158
+ expect(authService.getUser()).toEqual(mockUser);
159
+ expect(authService.getSession()).toEqual(mockSession);
160
+ expect(authService.isAuthenticated()).toBe(true);
161
+ });
162
+
163
+ it('should handle sign up errors', async () => {
164
+ const mockError = new AuthError('Email already registered');
165
+
166
+ mockSupabase.auth.signUp.mockResolvedValue({
167
+ data: { user: null, session: null },
168
+ error: mockError
169
+ });
170
+
171
+ const result = await authService.signUp('test@example.com', 'password');
172
+
173
+ expect(result.ok).toBe(false);
174
+ expect(result.error).toMatchObject({ message: mockError.message });
175
+ expect(authService.getError()).toEqual(mockError);
176
+ });
177
+ });
178
+
179
+ describe('Sign Out', () => {
180
+ it('should sign out user successfully', async () => {
181
+ // First sign in a user
182
+ const mockUser = { id: '1', email: 'test@example.com' };
183
+ const mockSession = { access_token: 'token', user: mockUser };
184
+
185
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
186
+ data: { user: mockUser, session: mockSession },
187
+ error: null
188
+ });
189
+
190
+ await authService.signIn('test@example.com', 'password');
191
+ expect(authService.isAuthenticated()).toBe(true);
192
+
193
+ // Then sign out
194
+ mockSupabase.auth.signOut.mockResolvedValue({
195
+ error: null
196
+ });
197
+
198
+ const result = await authService.signOut();
199
+
200
+ expect(result.ok).toBe(true);
201
+ expect(authService.getUser()).toBeNull();
202
+ expect(authService.getSession()).toBeNull();
203
+ expect(authService.isAuthenticated()).toBe(false);
204
+ });
205
+
206
+ it('should handle sign out errors', async () => {
207
+ const mockUser = { id: '1', email: 'test@example.com' };
208
+ const mockSession = { access_token: 'token', user: mockUser };
209
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
210
+ data: { user: mockUser, session: mockSession },
211
+ error: null
212
+ });
213
+ await authService.signIn('test@example.com', 'password');
214
+ expect(authService.getUser()).not.toBeNull();
215
+
216
+ const mockError = new AuthError('Sign out failed');
217
+ mockSupabase.auth.signOut
218
+ .mockResolvedValueOnce({ error: mockError })
219
+ .mockResolvedValueOnce({ error: null });
220
+
221
+ const result = await authService.signOut();
222
+
223
+ expect(result.ok).toBe(false);
224
+ expect(result.error).toMatchObject({ message: mockError.message });
225
+ expect(authService.getUser()).toBeNull();
226
+ expect(authService.getSession()).toBeNull();
227
+ });
228
+
229
+ it('should clear user and session when signOut throws', async () => {
230
+ const mockUser = { id: '1', email: 'test@example.com' };
231
+ const mockSession = { access_token: 'token', user: mockUser };
232
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
233
+ data: { user: mockUser, session: mockSession },
234
+ error: null
235
+ });
236
+ await authService.signIn('test@example.com', 'password');
237
+ expect(authService.getUser()).not.toBeNull();
238
+
239
+ const exceptionError = new Error('Network error');
240
+ mockSupabase.auth.signOut
241
+ .mockRejectedValueOnce(exceptionError)
242
+ .mockResolvedValueOnce({ error: null });
243
+
244
+ const result = await authService.signOut();
245
+
246
+ expect(result.ok).toBe(false);
247
+ expect(authService.getUser()).toBeNull();
248
+ expect(authService.getSession()).toBeNull();
249
+ });
250
+ });
251
+
252
+ describe('Password Reset', () => {
253
+ it('should reset password successfully', async () => {
254
+ mockSupabase.auth.resetPasswordForEmail.mockResolvedValue({
255
+ error: null
256
+ });
257
+
258
+ const result = await authService.resetPassword('test@example.com');
259
+
260
+ expect(result.ok).toBe(true);
261
+ expect(mockSupabase.auth.resetPasswordForEmail).toHaveBeenCalledWith('test@example.com');
262
+ });
263
+
264
+ it('should handle password reset errors', async () => {
265
+ const mockError = new AuthError('Email not found');
266
+
267
+ mockSupabase.auth.resetPasswordForEmail.mockResolvedValue({
268
+ error: mockError
269
+ });
270
+
271
+ const result = await authService.resetPassword('test@example.com');
272
+
273
+ expect(result.ok).toBe(false);
274
+ expect(result.error).toMatchObject({ message: mockError.message });
275
+ expect(authService.getError()).toEqual(mockError);
276
+ });
277
+ });
278
+
279
+ describe('Update Password', () => {
280
+ it('should update password successfully', async () => {
281
+ mockSupabase.auth.updateUser.mockResolvedValue({
282
+ error: null
283
+ });
284
+
285
+ const result = await authService.updatePassword('newpassword');
286
+
287
+ expect(result.ok).toBe(true);
288
+ expect(mockSupabase.auth.updateUser).toHaveBeenCalledWith({
289
+ password: 'newpassword'
290
+ });
291
+ });
292
+
293
+ it('should handle update password errors', async () => {
294
+ const mockError = new AuthError('Password too weak');
295
+
296
+ mockSupabase.auth.updateUser.mockResolvedValue({
297
+ error: mockError
298
+ });
299
+
300
+ const result = await authService.updatePassword('weak');
301
+
302
+ expect(result.ok).toBe(false);
303
+ expect(result.error).toMatchObject({ message: mockError.message });
304
+ expect(authService.getError()).toEqual(mockError);
305
+ });
306
+ });
307
+
308
+ describe('Refresh Session', () => {
309
+ it('should refresh session successfully', async () => {
310
+ mockSupabase.auth.refreshSession.mockResolvedValue({
311
+ error: null
312
+ });
313
+
314
+ const result = await authService.refreshSession();
315
+
316
+ expect(result.ok).toBe(true);
317
+ expect(mockSupabase.auth.refreshSession).toHaveBeenCalled();
318
+ });
319
+
320
+ it('should handle refresh session errors', async () => {
321
+ const mockError = new AuthError('Session expired');
322
+
323
+ mockSupabase.auth.refreshSession.mockResolvedValue({
324
+ error: mockError
325
+ });
326
+
327
+ const result = await authService.refreshSession();
328
+
329
+ expect(result.ok).toBe(false);
330
+ expect(result.error).toMatchObject({ message: mockError.message });
331
+ expect(authService.getError()).toEqual(mockError);
332
+ });
333
+ });
334
+
335
+ describe('State Management', () => {
336
+ it('should notify subscribers when state changes', async () => {
337
+ const mockUser = { id: '1', email: 'test@example.com' };
338
+ const mockSession = { access_token: 'token', user: mockUser };
339
+
340
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
341
+ data: { user: mockUser, session: mockSession },
342
+ error: null
343
+ });
344
+
345
+ const subscriber = vi.fn();
346
+ const unsubscribe = authService.subscribe(subscriber);
347
+
348
+ await authService.signIn('test@example.com', 'password');
349
+
350
+ expect(subscriber).toHaveBeenCalled();
351
+
352
+ unsubscribe();
353
+ });
354
+
355
+ it('should cleanup subscriptions on cleanup', () => {
356
+ const subscriber = vi.fn();
357
+ authService.subscribe(subscriber);
358
+
359
+ authService.cleanup();
360
+
361
+ // After cleanup, new state changes shouldn't notify subscribers
362
+ const mockUser = { id: '1', email: 'test@example.com' };
363
+ const mockSession = { access_token: 'token', user: mockUser };
364
+
365
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
366
+ data: { user: mockUser, session: mockSession },
367
+ error: null
368
+ });
369
+
370
+ authService.signIn('test@example.com', 'password');
371
+
372
+ // Subscriber should not be called after cleanup
373
+ expect(subscriber).not.toHaveBeenCalled();
374
+ });
375
+ });
376
+
377
+ describe('Error Handling', () => {
378
+ it('should handle network errors', async () => {
379
+ const networkError = new Error('Network error');
380
+
381
+ mockSupabase.auth.signInWithPassword.mockRejectedValue(networkError);
382
+
383
+ const result = await authService.signIn('test@example.com', 'password');
384
+
385
+ expect(result.ok).toBe(false);
386
+ expect(result.error.message).toBe('Network error');
387
+ });
388
+
389
+ it('should clear errors on successful operations', async () => {
390
+ // First cause an error
391
+ const mockError = new AuthError('Invalid credentials');
392
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
393
+ data: { user: null, session: null },
394
+ error: mockError
395
+ });
396
+
397
+ await authService.signIn('test@example.com', 'wrongpassword');
398
+ expect(authService.getError()).toEqual(mockError);
399
+
400
+ // Then succeed
401
+ const mockUser = { id: '1', email: 'test@example.com' };
402
+ const mockSession = { access_token: 'token', user: mockUser };
403
+
404
+ mockSupabase.auth.signInWithPassword.mockResolvedValue({
405
+ data: { user: mockUser, session: mockSession },
406
+ error: null
407
+ });
408
+
409
+ await authService.signIn('test@example.com', 'password');
410
+ expect(authService.getError()).toBeNull();
411
+ });
412
+
413
+ it('should handle exceptions during sign in', async () => {
414
+ const exceptionError = new Error('Unexpected exception');
415
+ mockSupabase.auth.signInWithPassword.mockRejectedValue(exceptionError);
416
+
417
+ const result = await authService.signIn('test@example.com', 'password');
418
+
419
+ expect(result.ok).toBe(false);
420
+ expect(result.error.message).toBe('Unexpected exception');
421
+ });
422
+
423
+ it('should handle exceptions during sign up', async () => {
424
+ const exceptionError = new Error('Unexpected exception');
425
+ mockSupabase.auth.signUp.mockRejectedValue(exceptionError);
426
+
427
+ const result = await authService.signUp('test@example.com', 'password');
428
+
429
+ expect(result.ok).toBe(false);
430
+ expect(result.error.message).toBe('Unexpected exception');
431
+ });
432
+
433
+ it('should handle exceptions during sign out', async () => {
434
+ const exceptionError = new Error('Unexpected exception');
435
+ mockSupabase.auth.signOut.mockRejectedValue(exceptionError);
436
+
437
+ const result = await authService.signOut();
438
+
439
+ expect(result.ok).toBe(false);
440
+ expect(result.error.message).toBe('Unexpected exception');
441
+ });
442
+
443
+ it('should handle exceptions during password reset', async () => {
444
+ const exceptionError = new Error('Unexpected exception');
445
+ mockSupabase.auth.resetPasswordForEmail.mockRejectedValue(exceptionError);
446
+
447
+ const result = await authService.resetPassword('test@example.com');
448
+
449
+ expect(result.ok).toBe(false);
450
+ });
451
+
452
+ it('should handle missing Supabase client on sign up', async () => {
453
+ const serviceWithoutClient = new AuthService(null as any);
454
+
455
+ const result = await serviceWithoutClient.signUp('test@example.com', 'password');
456
+
457
+ expect(result.ok).toBe(false);
458
+ expect(result.error.message).toBe('Supabase client not available');
459
+ });
460
+
461
+ it('should handle missing Supabase client on sign out', async () => {
462
+ const serviceWithoutClient = new AuthService(null as any);
463
+
464
+ const result = await serviceWithoutClient.signOut();
465
+
466
+ expect(result.ok).toBe(false);
467
+ expect(result.error.message).toBe('Supabase client not available');
468
+ });
469
+
470
+ it('should handle missing Supabase client on password reset', async () => {
471
+ const serviceWithoutClient = new AuthService(null as any);
472
+
473
+ const result = await serviceWithoutClient.resetPassword('test@example.com');
474
+
475
+ expect(result.ok).toBe(false);
476
+ expect(result.error.message).toBe('Supabase client not available');
477
+ });
478
+
479
+ it('should handle missing Supabase client on update password', async () => {
480
+ const serviceWithoutClient = new AuthService(null as any);
481
+
482
+ const result = await serviceWithoutClient.updatePassword('newpassword');
483
+
484
+ expect(result.ok).toBe(false);
485
+ expect(result.error.message).toBe('Supabase client not available');
486
+ });
487
+
488
+ it('should handle missing Supabase client on session refresh', async () => {
489
+ const serviceWithoutClient = new AuthService(null as any);
490
+
491
+ const result = await serviceWithoutClient.refreshSession();
492
+
493
+ expect(result.ok).toBe(false);
494
+ expect(result.error.message).toBe('Supabase client not available');
495
+ });
496
+ });
497
+
498
+ describe('Session Management Edge Cases', () => {
499
+ it('should handle session refresh with null data', async () => {
500
+ mockSupabase.auth.refreshSession.mockResolvedValue({
501
+ data: { session: null, user: null },
502
+ error: null
503
+ });
504
+
505
+ const result = await authService.refreshSession();
506
+
507
+ expect(result.ok).toBe(true);
508
+ expect(result.data?.user).toBeNull();
509
+ expect(result.data?.session).toBeNull();
510
+ expect(authService.getUser()).toBeNull();
511
+ expect(authService.getSession()).toBeNull();
512
+ });
513
+
514
+ it('should handle session refresh with user but no session by clearing both', async () => {
515
+ const mockUser = { id: '1', email: 'test@example.com' };
516
+
517
+ mockSupabase.auth.refreshSession.mockResolvedValue({
518
+ data: { session: null, user: mockUser },
519
+ error: null
520
+ });
521
+
522
+ const result = await authService.refreshSession();
523
+
524
+ // If there's no session, we should clear user state too
525
+ expect(result.ok).toBe(true);
526
+ expect(result.data?.user).toBeNull();
527
+ expect(result.data?.session).toBeNull();
528
+ expect(authService.getUser()).toBeNull();
529
+ expect(authService.getSession()).toBeNull();
530
+ });
531
+
532
+ it('should handle refresh session errors by clearing state', async () => {
533
+ const mockError = new AuthError('Session expired');
534
+
535
+ mockSupabase.auth.refreshSession.mockResolvedValue({
536
+ data: { session: null, user: null },
537
+ error: mockError
538
+ });
539
+
540
+ const result = await authService.refreshSession();
541
+
542
+ expect(result.ok).toBe(false);
543
+ expect(result.error).toMatchObject({ message: mockError.message });
544
+ expect(authService.getUser()).toBeNull();
545
+ expect(authService.getSession()).toBeNull();
546
+ expect(authService.isAuthenticated()).toBe(false);
547
+ });
548
+ });
549
+
550
+ describe('Initialization Edge Cases', () => {
551
+ it('should handle initialization without Supabase client', async () => {
552
+ const serviceWithoutClient = new AuthService(null as any);
553
+ await serviceWithoutClient.initialize();
554
+
555
+ expect(mockSupabase.auth.getSession).not.toHaveBeenCalled();
556
+ expect(mockSupabase.auth.onAuthStateChange).not.toHaveBeenCalled();
557
+ });
558
+
559
+ it('should handle initialization with getSession error', async () => {
560
+ const sessionError = new AuthError('Session error');
561
+ mockSupabase.auth.getSession.mockResolvedValue({
562
+ data: { session: null },
563
+ error: sessionError
564
+ });
565
+ mockSupabase.auth.getUser.mockResolvedValue({
566
+ data: { user: null },
567
+ error: null
568
+ });
569
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
570
+ data: { subscription: { unsubscribe: vi.fn() } }
571
+ });
572
+
573
+ await authService.initialize();
574
+
575
+ expect(mockSupabase.auth.getSession).toHaveBeenCalled();
576
+ expect(mockSupabase.auth.getUser).toHaveBeenCalled();
577
+ });
578
+
579
+ it('should not call getUser when getSession succeeds with no session (prevents AuthSessionMissingError)', async () => {
580
+ mockSupabase.auth.getSession.mockResolvedValue({
581
+ data: { session: null },
582
+ error: null
583
+ });
584
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
585
+ data: { subscription: { unsubscribe: vi.fn() } }
586
+ });
587
+
588
+ await authService.initialize();
589
+
590
+ // When getSession succeeds with no session, getUser is NOT called to prevent
591
+ // AuthSessionMissingError from being raised on public pages (e.g., login page)
592
+ // This is intentional behavior to avoid noisy error banners for benign unauthenticated states
593
+ expect(mockSupabase.auth.getSession).toHaveBeenCalled();
594
+ expect(mockSupabase.auth.getUser).not.toHaveBeenCalled();
595
+ });
596
+
597
+ it('should restore session from storage during initialization', async () => {
598
+ const mockUser = { id: '1', email: 'test@example.com' };
599
+ const mockSession = { access_token: 'token', user: mockUser };
600
+
601
+ mockSupabase.auth.getSession.mockResolvedValue({
602
+ data: { session: mockSession },
603
+ error: null
604
+ });
605
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
606
+ data: { subscription: { unsubscribe: vi.fn() } }
607
+ });
608
+
609
+ await authService.initialize();
610
+
611
+ expect(authService.getUser()).toEqual(mockUser);
612
+ expect(authService.getSession()).toEqual(mockSession);
613
+ expect(authService.isAuthenticated()).toBe(true);
614
+ });
615
+
616
+ it('should handle auth state change unsubscribe gracefully', () => {
617
+ const unsubscribeFn = vi.fn();
618
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
619
+ data: { subscription: { unsubscribe: unsubscribeFn } }
620
+ });
621
+
622
+ authService.cleanup();
623
+
624
+ // Should not throw error
625
+ expect(unsubscribeFn).not.toHaveBeenCalled();
626
+ });
627
+
628
+ it('should handle auth state change events correctly', async () => {
629
+ const mockUser = { id: '1', email: 'test@example.com' };
630
+ const mockSession = { access_token: 'token', user: mockUser };
631
+
632
+ let authStateCallback: any;
633
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
634
+ authStateCallback = callback;
635
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
636
+ });
637
+
638
+ await authService.initialize();
639
+
640
+ // Simulate SIGNED_IN event
641
+ if (authStateCallback) {
642
+ authStateCallback('SIGNED_IN', mockSession);
643
+ expect(authService.getUser()).toEqual(mockUser);
644
+ expect(authService.getSession()).toEqual(mockSession);
645
+ }
646
+
647
+ // Simulate SIGNED_OUT event
648
+ if (authStateCallback) {
649
+ authStateCallback('SIGNED_OUT', null);
650
+ expect(authService.getUser()).toBeNull();
651
+ expect(authService.getSession()).toBeNull();
652
+ }
653
+
654
+ // Simulate TOKEN_REFRESHED event
655
+ const refreshedSession = { ...mockSession, access_token: 'new_token' };
656
+ if (authStateCallback) {
657
+ authStateCallback('TOKEN_REFRESHED', refreshedSession);
658
+ expect(authService.getSession()).toEqual(refreshedSession);
659
+ }
660
+
661
+ // Simulate INITIAL_SESSION event
662
+ const initialSession = { access_token: 'initial_token', user: mockUser };
663
+ if (authStateCallback) {
664
+ authStateCallback('INITIAL_SESSION', initialSession);
665
+ expect(authService.getSession()).toEqual(initialSession);
666
+ }
667
+ });
668
+
669
+ it('should handle errors in auth state change callback', async () => {
670
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
671
+
672
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
673
+ // Simulate error in callback
674
+ try {
675
+ callback('INITIAL_SESSION', null);
676
+ } catch (_error) {
677
+ // Error is expected to be caught and logged
678
+ }
679
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
680
+ });
681
+
682
+ await authService.initialize();
683
+
684
+ expect(consoleWarnSpy).not.toHaveBeenCalled();
685
+ consoleWarnSpy.mockRestore();
686
+ });
687
+ });
688
+
689
+ describe('Get Session with Null User', () => {
690
+ it('should handle session with null user object', () => {
691
+ const mockSessionWithNullUser = { access_token: 'token', user: null };
692
+
693
+ // This would be set via internal state
694
+ (authService as any).session = mockSessionWithNullUser;
695
+
696
+ expect(authService.getSession()).toEqual(mockSessionWithNullUser);
697
+ expect(authService.getUser()).toBeNull();
698
+ expect(authService.isAuthenticated()).toBe(false);
699
+ });
700
+ });
701
+
702
+ describe('Automatic Session Tracking', () => {
703
+ beforeEach(() => {
704
+ // Mock rpc function for session tracking
705
+ (mockSupabase as any).rpc = vi.fn();
706
+ // Mock from().select() chain for app ID resolution
707
+ (mockSupabase as any).from = vi.fn().mockReturnValue({
708
+ select: vi.fn().mockReturnValue({
709
+ eq: vi.fn().mockReturnValue({
710
+ eq: vi.fn().mockReturnValue({
711
+ single: vi.fn().mockResolvedValue({
712
+ data: { id: 'app-id-123' },
713
+ error: null
714
+ })
715
+ })
716
+ })
717
+ })
718
+ });
719
+ });
720
+
721
+ it('should track login session automatically on SIGNED_IN event', async () => {
722
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
723
+ const mockSession = { access_token: 'token', user: mockUser };
724
+
725
+ (mockSupabase as any).rpc.mockResolvedValue({ error: null });
726
+
727
+ let authStateCallback: any;
728
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
729
+ authStateCallback = callback;
730
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
731
+ });
732
+
733
+ // Initialize with appName to test app ID resolution
734
+ const authServiceWithApp = new AuthService(mockSupabase as any, 'TEST_APP');
735
+ await authServiceWithApp.initialize();
736
+
737
+ // Simulate SIGNED_IN event
738
+ if (authStateCallback) {
739
+ authStateCallback('SIGNED_IN', mockSession);
740
+
741
+ // Wait a bit for async tracking to complete
742
+ await new Promise(resolve => setTimeout(resolve, 100));
743
+
744
+ // Verify rbac_session_track was called with correct parameters
745
+ expect((mockSupabase as any).rpc).toHaveBeenCalledWith('rbac_session_track', expect.objectContaining({
746
+ p_user_id: 'user-123',
747
+ p_session_type: 'login',
748
+ p_event_id: null,
749
+ p_app_id: 'app-id-123', // Should be resolved from appName
750
+ // p_user_agent, p_device_fingerprint, p_ip_address may be undefined in test environment
751
+ }));
752
+ }
753
+
754
+ authServiceWithApp.cleanup();
755
+ });
756
+
757
+ it('should track logout session automatically on SIGNED_OUT event', async () => {
758
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
759
+ const mockSession = { access_token: 'token', user: mockUser };
760
+
761
+ (mockSupabase as any).rpc.mockResolvedValue({ error: null });
762
+
763
+ let authStateCallback: any;
764
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
765
+ authStateCallback = callback;
766
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
767
+ });
768
+
769
+ const authServiceWithApp = new AuthService(mockSupabase as any, 'TEST_APP');
770
+ await authServiceWithApp.initialize();
771
+
772
+ // Simulate SIGNED_OUT event
773
+ if (authStateCallback) {
774
+ authStateCallback('SIGNED_OUT', mockSession);
775
+
776
+ // Wait a bit for async tracking to complete
777
+ await new Promise(resolve => setTimeout(resolve, 100));
778
+
779
+ // Verify rbac_session_track was called with logout type
780
+ expect((mockSupabase as any).rpc).toHaveBeenCalledWith('rbac_session_track', expect.objectContaining({
781
+ p_user_id: 'user-123',
782
+ p_session_type: 'logout',
783
+ }));
784
+ }
785
+
786
+ authServiceWithApp.cleanup();
787
+ });
788
+
789
+ it('should NOT track session on TOKEN_REFRESHED event (to avoid duplicate login records)', async () => {
790
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
791
+ const mockSession = { access_token: 'new_token', user: mockUser };
792
+
793
+ (mockSupabase as any).rpc.mockResolvedValue({ error: null });
794
+
795
+ let authStateCallback: any;
796
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
797
+ authStateCallback = callback;
798
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
799
+ });
800
+
801
+ const authServiceWithApp = new AuthService(mockSupabase as any, 'TEST_APP');
802
+ await authServiceWithApp.initialize();
803
+
804
+ // Simulate TOKEN_REFRESHED event
805
+ if (authStateCallback) {
806
+ authStateCallback('TOKEN_REFRESHED', mockSession);
807
+
808
+ // Wait a bit for any async operations
809
+ await new Promise(resolve => setTimeout(resolve, 100));
810
+
811
+ // Verify rbac_session_track was NOT called
812
+ expect((mockSupabase as any).rpc).not.toHaveBeenCalled();
813
+ }
814
+
815
+ authServiceWithApp.cleanup();
816
+ });
817
+
818
+ it('should handle tracking errors gracefully without breaking authentication', async () => {
819
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
820
+ const mockSession = { access_token: 'token', user: mockUser };
821
+
822
+ // Mock rpc to reject (this will trigger the catch block in trackSession)
823
+ (mockSupabase as any).rpc = vi.fn().mockRejectedValue(new Error('Tracking failed'));
824
+
825
+ let authStateCallback: any;
826
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
827
+ authStateCallback = callback;
828
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
829
+ });
830
+
831
+ const authServiceWithApp = new AuthService(mockSupabase as any, 'TEST_APP');
832
+ await authServiceWithApp.initialize();
833
+
834
+ // Simulate SIGNED_IN event
835
+ if (authStateCallback) {
836
+ authStateCallback('SIGNED_IN', mockSession);
837
+
838
+ // Wait for async tracking to complete (trackSession is async)
839
+ // The catch block in trackSession will log the error
840
+ // Note: The logger may be called in the .catch() handler with "Failed to track"
841
+ // or in the catch block with "Error tracking"
842
+ await new Promise(resolve => setTimeout(resolve, 500));
843
+
844
+ // Check for either error message pattern
845
+ const warnCalls = mockLoggerFunctions.warn.mock.calls;
846
+ const hasErrorTracking = warnCalls.some(call =>
847
+ call[0] === 'AuthService' &&
848
+ typeof call[1] === 'string' &&
849
+ call[1].includes('Error tracking')
850
+ );
851
+ const hasFailedToTrack = warnCalls.some(call =>
852
+ call[0] === 'AuthService' &&
853
+ typeof call[1] === 'string' &&
854
+ call[1].includes('Failed to track')
855
+ );
856
+
857
+ expect(hasErrorTracking || hasFailedToTrack).toBe(true);
858
+ expect(mockLoggerFunctions.warn).toHaveBeenCalled();
859
+ expect(authServiceWithApp.isAuthenticated()).toBe(true);
860
+ }
861
+ authServiceWithApp.cleanup();
862
+ });
863
+
864
+ it('should work without appName (app_id will be null)', async () => {
865
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
866
+ const mockSession = { access_token: 'token', user: mockUser };
867
+
868
+ (mockSupabase as any).rpc.mockResolvedValue({ error: null });
869
+
870
+ let authStateCallback: any;
871
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
872
+ authStateCallback = callback;
873
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
874
+ });
875
+
876
+ // Initialize without appName
877
+ await authService.initialize();
878
+
879
+ // Simulate SIGNED_IN event
880
+ if (authStateCallback) {
881
+ authStateCallback('SIGNED_IN', mockSession);
882
+
883
+ // Wait a bit for async tracking to complete
884
+ await new Promise(resolve => setTimeout(resolve, 100));
885
+
886
+ // Verify rbac_session_track was called with null app_id
887
+ expect((mockSupabase as any).rpc).toHaveBeenCalledWith('rbac_session_track', expect.objectContaining({
888
+ p_user_id: 'user-123',
889
+ p_session_type: 'login',
890
+ p_app_id: undefined, // Should be undefined when appName not provided
891
+ }));
892
+ }
893
+ });
894
+ });
895
+
896
+ describe('Session Restoration Edge Cases', () => {
897
+ it('should handle getSession throwing exception', async () => {
898
+ mockSupabase.auth.getSession.mockRejectedValue(new Error('getSession exception'));
899
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
900
+ data: { subscription: { unsubscribe: vi.fn() } }
901
+ });
902
+
903
+ await authService.initialize();
904
+
905
+ // Should handle exception gracefully
906
+ expect(mockSupabase.auth.getSession).toHaveBeenCalled();
907
+ });
908
+
909
+ it('should handle getUser when getSession fails', async () => {
910
+ const sessionError = new AuthError('Session error');
911
+ mockSupabase.auth.getSession.mockResolvedValue({
912
+ data: { session: null },
913
+ error: sessionError
914
+ });
915
+ mockSupabase.auth.getUser.mockResolvedValue({
916
+ data: { user: null },
917
+ error: null
918
+ });
919
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
920
+ data: { subscription: { unsubscribe: vi.fn() } }
921
+ });
922
+
923
+ await authService.initialize();
924
+
925
+ expect(mockSupabase.auth.getUser).toHaveBeenCalled();
926
+ });
927
+
928
+ it('should handle getUser also failing', async () => {
929
+ const sessionError = new AuthError('Session error');
930
+ mockSupabase.auth.getSession.mockResolvedValue({
931
+ data: { session: null },
932
+ error: sessionError
933
+ });
934
+ mockSupabase.auth.getUser.mockRejectedValue(new Error('getUser exception'));
935
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
936
+ data: { subscription: { unsubscribe: vi.fn() } }
937
+ });
938
+
939
+ await authService.initialize();
940
+
941
+ // Should handle both failures gracefully
942
+ expect(mockSupabase.auth.getUser).toHaveBeenCalled();
943
+ });
944
+
945
+ it('should handle session restoration timeout', async () => {
946
+ // Mock getSession to hang (simulate timeout scenario)
947
+ mockSupabase.auth.getSession.mockImplementation(() => {
948
+ return new Promise(() => {
949
+ // Never resolves - will timeout after 5 seconds in real scenario
950
+ });
951
+ });
952
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
953
+ data: { subscription: { unsubscribe: vi.fn() } }
954
+ });
955
+
956
+ // Start initialization (will hang waiting for getSession)
957
+ const initPromise = authService.initialize();
958
+
959
+ // Use a timeout to simulate the service's internal timeout
960
+ const timeoutPromise = new Promise((_, reject) => {
961
+ setTimeout(() => reject(new Error('Test timeout')), 100);
962
+ });
963
+
964
+ // Race between initialization and test timeout
965
+ try {
966
+ await Promise.race([initPromise, timeoutPromise]);
967
+ } catch (_error) {
968
+ // Expected to timeout in test
969
+ }
970
+
971
+ // Verify that restoration state is managed
972
+ const restorationState = authService.getSessionRestorationState();
973
+ expect(restorationState).toBeDefined();
974
+ }, 1000);
975
+
976
+ it('should finish restoration with timeout error', async () => {
977
+ // Mock getSession to hang (simulate timeout scenario)
978
+ mockSupabase.auth.getSession.mockImplementation(() => {
979
+ return new Promise(() => {
980
+ // Never resolves - will timeout after 5 seconds in real scenario
981
+ });
982
+ });
983
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
984
+ data: { subscription: { unsubscribe: vi.fn() } }
985
+ });
986
+
987
+ // Start initialization (will hang waiting for getSession)
988
+ const initPromise = authService.initialize();
989
+
990
+ // Use a timeout to simulate the service's internal timeout
991
+ const timeoutPromise = new Promise((_, reject) => {
992
+ setTimeout(() => reject(new Error('Test timeout')), 100);
993
+ });
994
+
995
+ // Race between initialization and test timeout
996
+ try {
997
+ await Promise.race([initPromise, timeoutPromise]);
998
+ } catch (_error) {
999
+ // Expected to timeout in test
1000
+ }
1001
+
1002
+ // Verify that restoration state is managed
1003
+ const restorationState = authService.getSessionRestorationState();
1004
+ expect(restorationState).toBeDefined();
1005
+ }, 1000);
1006
+
1007
+ it('should handle restoration error during initialization', async () => {
1008
+ const restorationError = new Error('Restoration failed');
1009
+ mockSupabase.auth.getSession.mockRejectedValue(restorationError);
1010
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
1011
+ data: { subscription: { unsubscribe: vi.fn() } }
1012
+ });
1013
+
1014
+ await authService.initialize();
1015
+
1016
+ const restorationState = authService.getSessionRestorationState();
1017
+ expect(restorationState.restorationError).toBeDefined();
1018
+ });
1019
+
1020
+ it('should reset restoration state when valid session arrives after timeout', async () => {
1021
+ let authStateCallback: any;
1022
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1023
+ authStateCallback = callback;
1024
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1025
+ });
1026
+
1027
+ // Mock getSession to fail initially
1028
+ mockSupabase.auth.getSession.mockRejectedValue(new Error('Timeout'));
1029
+
1030
+ await authService.initialize();
1031
+
1032
+ // Simulate INITIAL_SESSION arriving after timeout
1033
+ const mockSession = { access_token: 'token', user: { id: '1', email: 'test@example.com' } };
1034
+ if (authStateCallback) {
1035
+ authStateCallback('INITIAL_SESSION', mockSession);
1036
+ }
1037
+
1038
+ // Wait a bit for state to update
1039
+ await new Promise(resolve => setTimeout(resolve, 10));
1040
+
1041
+ const restorationState = authService.getSessionRestorationState();
1042
+ expect(restorationState.restorationComplete).toBe(true);
1043
+ });
1044
+ });
1045
+
1046
+ describe('Error Handlers', () => {
1047
+ it('should setup error handlers on initialization', async () => {
1048
+ const addEventListenerSpy = vi.spyOn(window, 'addEventListener');
1049
+
1050
+ mockSupabase.auth.getSession.mockResolvedValue({
1051
+ data: { session: null },
1052
+ error: null
1053
+ });
1054
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
1055
+ data: { subscription: { unsubscribe: vi.fn() } }
1056
+ });
1057
+
1058
+ await authService.initialize();
1059
+
1060
+ // Error handlers should be set up
1061
+ expect(addEventListenerSpy).toHaveBeenCalledWith('error', expect.any(Function));
1062
+ expect(addEventListenerSpy).toHaveBeenCalledWith('unhandledrejection', expect.any(Function));
1063
+
1064
+ addEventListenerSpy.mockRestore();
1065
+ });
1066
+
1067
+ it('should suppress AuthSessionMissingError in error handler', async () => {
1068
+ const preventDefaultSpy = vi.fn();
1069
+
1070
+ mockSupabase.auth.getSession.mockResolvedValue({
1071
+ data: { session: null },
1072
+ error: null
1073
+ });
1074
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
1075
+ data: { subscription: { unsubscribe: vi.fn() } }
1076
+ });
1077
+
1078
+ await authService.initialize();
1079
+
1080
+ // Trigger error handler
1081
+ const errorEvent = new ErrorEvent('error', { error: { message: 'AuthSessionMissingError' } as any });
1082
+ window.dispatchEvent(errorEvent);
1083
+
1084
+ // Error should be suppressed
1085
+ expect(preventDefaultSpy).not.toHaveBeenCalled(); // In test environment, preventDefault may not work
1086
+ });
1087
+
1088
+ it('should suppress AuthSessionMissingError in unhandled rejection', async () => {
1089
+ mockSupabase.auth.getSession.mockResolvedValue({
1090
+ data: { session: null },
1091
+ error: null
1092
+ });
1093
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
1094
+ data: { subscription: { unsubscribe: vi.fn() } }
1095
+ });
1096
+
1097
+ await authService.initialize();
1098
+
1099
+ // Create a promise that will be rejected
1100
+ const rejectedPromise = Promise.reject(new Error('AuthSessionMissingError'));
1101
+
1102
+ // Catch the rejection to prevent it from being unhandled
1103
+ rejectedPromise.catch(() => {
1104
+ // The error handler should suppress this
1105
+ });
1106
+
1107
+ // Trigger unhandled rejection using a custom event
1108
+ const rejectionEvent = new Event('unhandledrejection') as any;
1109
+ rejectionEvent.promise = rejectedPromise;
1110
+ rejectionEvent.reason = { message: 'AuthSessionMissingError' };
1111
+
1112
+ // The handler should be set up and will suppress the error
1113
+ window.dispatchEvent(rejectionEvent);
1114
+
1115
+ // Test passes if no error propagates
1116
+ expect(true).toBe(true);
1117
+ });
1118
+
1119
+ it('should handle window undefined environment', async () => {
1120
+ const originalWindow = global.window;
1121
+ // @ts-expect-error Deleting global.window for SSR/window-undefined test
1122
+ delete global.window;
1123
+
1124
+ mockSupabase.auth.getSession.mockResolvedValue({
1125
+ data: { session: null },
1126
+ error: null
1127
+ });
1128
+ mockSupabase.auth.onAuthStateChange.mockReturnValue({
1129
+ data: { subscription: { unsubscribe: vi.fn() } }
1130
+ });
1131
+
1132
+ // Should not throw error
1133
+ await expect(authService.initialize()).resolves.toBeUndefined();
1134
+
1135
+ global.window = originalWindow;
1136
+ });
1137
+ });
1138
+
1139
+ describe('Session Tracking Edge Cases', () => {
1140
+ it('should handle tracking when app lookup fails', async () => {
1141
+ (mockSupabase as any).rpc = vi.fn();
1142
+ (mockSupabase as any).from = vi.fn().mockReturnValue({
1143
+ select: vi.fn().mockReturnValue({
1144
+ eq: vi.fn().mockReturnValue({
1145
+ eq: vi.fn().mockReturnValue({
1146
+ single: vi.fn().mockResolvedValue({
1147
+ data: null,
1148
+ error: { message: 'App not found' }
1149
+ })
1150
+ })
1151
+ })
1152
+ })
1153
+ });
1154
+
1155
+ let authStateCallback: any;
1156
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1157
+ authStateCallback = callback;
1158
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1159
+ });
1160
+
1161
+ const authServiceWithApp = new AuthService(mockSupabase as any, 'TEST_APP');
1162
+ await authServiceWithApp.initialize();
1163
+
1164
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
1165
+ const mockSession = { access_token: 'token', user: mockUser };
1166
+
1167
+ if (authStateCallback) {
1168
+ authStateCallback('SIGNED_IN', mockSession);
1169
+
1170
+ await new Promise(resolve => setTimeout(resolve, 100));
1171
+
1172
+ // Should still track with null app_id
1173
+ expect((mockSupabase as any).rpc).toHaveBeenCalledWith('rbac_session_track', expect.objectContaining({
1174
+ p_app_id: undefined
1175
+ }));
1176
+ }
1177
+
1178
+ authServiceWithApp.cleanup();
1179
+ });
1180
+
1181
+ it('should handle tracking when RPC fails', async () => {
1182
+ vi.clearAllMocks();
1183
+ (mockSupabase as any).rpc = vi.fn().mockResolvedValue({
1184
+ error: { message: 'RPC failed' }
1185
+ });
1186
+ (mockSupabase as any).from = vi.fn().mockReturnValue({
1187
+ select: vi.fn().mockReturnValue({
1188
+ eq: vi.fn().mockReturnValue({
1189
+ eq: vi.fn().mockReturnValue({
1190
+ single: vi.fn().mockResolvedValue({
1191
+ data: { id: 'app-id-123' },
1192
+ error: null
1193
+ })
1194
+ })
1195
+ })
1196
+ })
1197
+ });
1198
+
1199
+ let authStateCallback: any;
1200
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1201
+ authStateCallback = callback;
1202
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1203
+ });
1204
+
1205
+ const authServiceWithApp = new AuthService(mockSupabase as any, 'TEST_APP');
1206
+ await authServiceWithApp.initialize();
1207
+
1208
+ const mockUser = { id: 'user-123', email: 'test@example.com' };
1209
+ const mockSession = { access_token: 'token', user: mockUser };
1210
+
1211
+ if (authStateCallback) {
1212
+ authStateCallback('SIGNED_IN', mockSession);
1213
+
1214
+ // Wait for async tracking to complete
1215
+ await new Promise(resolve => setTimeout(resolve, 200));
1216
+ expect(mockLoggerFunctions.warn).toHaveBeenCalledWith(
1217
+ 'AuthService',
1218
+ expect.stringContaining('Failed to track'),
1219
+ expect.anything()
1220
+ );
1221
+ }
1222
+ authServiceWithApp.cleanup();
1223
+ });
1224
+
1225
+ it('should not track when session is null', async () => {
1226
+ (mockSupabase as any).rpc = vi.fn();
1227
+
1228
+ let authStateCallback: any;
1229
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1230
+ authStateCallback = callback;
1231
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1232
+ });
1233
+
1234
+ await authService.initialize();
1235
+
1236
+ if (authStateCallback) {
1237
+ authStateCallback('SIGNED_OUT', null);
1238
+
1239
+ await new Promise(resolve => setTimeout(resolve, 100));
1240
+
1241
+ // Should not track when session is null
1242
+ expect((mockSupabase as any).rpc).not.toHaveBeenCalled();
1243
+ }
1244
+ });
1245
+
1246
+ it('should not track when user is null in session', async () => {
1247
+ (mockSupabase as any).rpc = vi.fn();
1248
+
1249
+ let authStateCallback: any;
1250
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1251
+ authStateCallback = callback;
1252
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1253
+ });
1254
+
1255
+ await authService.initialize();
1256
+
1257
+ if (authStateCallback) {
1258
+ const sessionWithoutUser = { access_token: 'token', user: null };
1259
+ authStateCallback('SIGNED_IN', sessionWithoutUser);
1260
+
1261
+ await new Promise(resolve => setTimeout(resolve, 100));
1262
+
1263
+ // Should not track when user is null
1264
+ expect((mockSupabase as any).rpc).not.toHaveBeenCalled();
1265
+ }
1266
+ });
1267
+ });
1268
+
1269
+ describe('Auth State Change Events', () => {
1270
+ it('should handle INITIAL_SESSION event with null session', async () => {
1271
+ let authStateCallback: any;
1272
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1273
+ authStateCallback = callback;
1274
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1275
+ });
1276
+
1277
+ mockSupabase.auth.getSession.mockResolvedValue({
1278
+ data: { session: null },
1279
+ error: null
1280
+ });
1281
+
1282
+ await authService.initialize();
1283
+
1284
+ if (authStateCallback) {
1285
+ authStateCallback('INITIAL_SESSION', null);
1286
+
1287
+ expect(authService.getUser()).toBeNull();
1288
+ expect(authService.getSession()).toBeNull();
1289
+ }
1290
+ });
1291
+
1292
+ it('should handle TOKEN_REFRESHED event', async () => {
1293
+ let authStateCallback: any;
1294
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1295
+ authStateCallback = callback;
1296
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1297
+ });
1298
+
1299
+ mockSupabase.auth.getSession.mockResolvedValue({
1300
+ data: { session: null },
1301
+ error: null
1302
+ });
1303
+
1304
+ await authService.initialize();
1305
+
1306
+ const mockUser = { id: '1', email: 'test@example.com' };
1307
+ const refreshedSession = { access_token: 'new_token', user: mockUser };
1308
+
1309
+ if (authStateCallback) {
1310
+ authStateCallback('TOKEN_REFRESHED', refreshedSession);
1311
+
1312
+ expect(authService.getSession()).toEqual(refreshedSession);
1313
+ expect(authService.getUser()).toEqual(mockUser);
1314
+ }
1315
+ });
1316
+
1317
+ it('should handle errors in auth state change callback', async () => {
1318
+ const consoleWarnSpy = vi.spyOn(console, 'warn').mockImplementation(() => {});
1319
+
1320
+ mockSupabase.auth.onAuthStateChange.mockImplementation((callback) => {
1321
+ try {
1322
+ // Simulate error in callback
1323
+ callback('INITIAL_SESSION', null);
1324
+ } catch (_error) {
1325
+ // Error should be caught
1326
+ }
1327
+ return { data: { subscription: { unsubscribe: vi.fn() } } };
1328
+ });
1329
+
1330
+ mockSupabase.auth.getSession.mockResolvedValue({
1331
+ data: { session: null },
1332
+ error: null
1333
+ });
1334
+
1335
+ await authService.initialize();
1336
+
1337
+ // Should handle error gracefully
1338
+ expect(consoleWarnSpy).not.toHaveBeenCalled();
1339
+
1340
+ consoleWarnSpy.mockRestore();
1341
+ });
1342
+ });
1343
+
1344
+ describe('Session Restoration State', () => {
1345
+ it('should return session restoration state', () => {
1346
+ const state = authService.getSessionRestorationState();
1347
+
1348
+ expect(state).toHaveProperty('isRestoring');
1349
+ expect(state).toHaveProperty('restorationComplete');
1350
+ expect(state).toHaveProperty('restorationError');
1351
+ });
1352
+
1353
+ it('should return copy of restoration state', () => {
1354
+ const state1 = authService.getSessionRestorationState();
1355
+ const state2 = authService.getSessionRestorationState();
1356
+
1357
+ // Should be different objects (copies)
1358
+ expect(state1).not.toBe(state2);
1359
+ expect(state1).toEqual(state2);
1360
+ });
1361
+ });
1362
+ });