@jmruthers/pace-core 0.6.10 → 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 (726) 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 +13 -3
  5. package/audit-tool/audits/03-architecture.cjs +78 -4
  6. package/audit-tool/audits/04-code-quality.cjs +9 -2
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +105 -14
  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 +1 -0
  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 +41 -7
  19. package/cursor-rules/06-security-rbac.mdc +2 -1
  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-SAXFG4XI.js → DataTable-EFYP2QLE.js} +10 -7
  24. package/dist/{InactivityServiceProvider-DHryoh6K.d.ts → InactivityServiceProvider-BbxwwDz1.d.ts} +10 -1
  25. package/dist/{UnifiedAuthProvider-CiBAl9-s.d.ts → UnifiedAuthProvider-Bkt_tzdS.d.ts} +56 -24
  26. package/dist/{api-F47QJ7FX.js → api-BZR2CYXL.js} +3 -2
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/{audit-Z6ZZBWLU.js → audit-HI2DHUVU.js} +2 -1
  29. package/dist/{auth-BZOJqrdd.d.ts → auth-JvdRVaud.d.ts} +1 -1
  30. package/dist/{chunk-KSNLMI7N.js → chunk-2DL2WSOE.js} +1 -155
  31. package/dist/{chunk-MPY44PWB.js → chunk-2OEVOGGR.js} +4648 -3560
  32. package/dist/chunk-44CNXN4P.js +15 -0
  33. package/dist/{chunk-Y4PF6HIM.js → chunk-4R3T5ENU.js} +867 -786
  34. package/dist/{chunk-LNHFAF4X.js → chunk-7A6IMHH2.js} +289 -247
  35. package/dist/chunk-CU2BU2MQ.js +2 -0
  36. package/dist/{chunk-JJEYZ3DX.js → chunk-D6BMFMQZ.js} +37 -2
  37. package/dist/{chunk-BCTXBU6U.js → chunk-ENLXB7GP.js} +88 -71
  38. package/dist/{chunk-FBZ7U3ID.js → chunk-J2KQK6DG.js} +937 -987
  39. package/dist/{chunk-TFIPNIPE.js → chunk-KJXRL3XE.js} +3300 -2245
  40. package/dist/{chunk-3GWSPISD.js → chunk-L5LFKKLJ.js} +1 -1
  41. package/dist/{chunk-X5EAU5G7.js → chunk-PCSHBLPB.js} +132 -114
  42. package/dist/{chunk-NIU6DPQV.js → chunk-QRYSEPHB.js} +2 -0
  43. package/dist/{chunk-KYURMOQM.js → chunk-V7FTM2LU.js} +423 -320
  44. package/dist/chunk-WY6Y7KC3.js +264 -0
  45. package/dist/{chunk-FN52B75D.js → chunk-XOJME5T7.js} +176 -15
  46. package/dist/{chunk-7YDC7LMU.js → chunk-XPFVT3GN.js} +71 -66
  47. package/dist/{chunk-66R6RLUZ.js → chunk-YFTFFJIV.js} +3 -3
  48. package/dist/{chunk-W46INAVW.js → chunk-YYTWKVHO.js} +688 -570
  49. package/dist/components.d.ts +8 -7
  50. package/dist/components.js +17 -15
  51. package/dist/{database.generated-DT8JTZiP.d.ts → database.generated-qkdoiVrJ.d.ts} +45 -10
  52. package/dist/eslint-rules/index.cjs +3 -0
  53. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  54. package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
  55. package/dist/{event-WTAQuGcq.d.ts → event-BfCox3N2.d.ts} +36 -10
  56. package/dist/{file-reference-BavO2eQj.d.ts → file-reference-DU1hcawx.d.ts} +29 -13
  57. package/dist/hooks.d.ts +22 -9
  58. package/dist/hooks.js +34 -25
  59. package/dist/icons/index.d.ts +1 -0
  60. package/dist/icons/index.js +1 -0
  61. package/dist/index.d.ts +66 -177
  62. package/dist/index.js +316 -340
  63. package/dist/pagination-BW1mqywp.d.ts +201 -0
  64. package/dist/providers.d.ts +6 -5
  65. package/dist/providers.js +5 -3
  66. package/dist/rbac/index.d.ts +123 -138
  67. package/dist/rbac/index.js +10 -8
  68. package/dist/theming/runtime.d.ts +19 -2
  69. package/dist/theming/runtime.js +1 -1
  70. package/dist/{timezone-K-ptz3HO.d.ts → timezone-BTWWXKVY.d.ts} +1 -1
  71. package/dist/types.d.ts +17 -10
  72. package/dist/types.js +1 -0
  73. package/dist/{usePublicPageContext-vxBlEHO9.d.ts → usePublicPageContext-B91dGYW1.d.ts} +433 -356
  74. package/dist/{usePublicRouteParams-G3Ks53mk.d.ts → usePublicRouteParams-BgV6VhMi.d.ts} +73 -4
  75. package/dist/utils.d.ts +163 -145
  76. package/dist/utils.js +42 -25
  77. package/docs/api/modules.md +782 -643
  78. package/docs/api-reference/rpc-functions.md +12 -3
  79. package/docs/core-concepts/rbac-system.md +8 -0
  80. package/docs/getting-started/cursor-rules.md +17 -20
  81. package/docs/getting-started/dependencies.md +1 -1
  82. package/docs/getting-started/setup.md +235 -0
  83. package/docs/implementation-guides/authentication.md +27 -0
  84. package/docs/implementation-guides/data-tables.md +176 -3
  85. package/docs/migration/ApiResult-migration.md +25 -0
  86. package/docs/rbac/api-reference.md +33 -31
  87. package/docs/standards/0-standards-overview.md +50 -15
  88. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  89. package/docs/standards/2-project-structure-standards.md +33 -16
  90. package/docs/standards/3-architecture-standards.md +41 -1
  91. package/docs/standards/4-code-quality-standards.md +26 -6
  92. package/docs/standards/5-styling-standards.md +35 -1
  93. package/docs/standards/6-security-rbac-standards.md +66 -0
  94. package/docs/standards/7-api-tech-stack-standards.md +25 -14
  95. package/docs/standards/8-testing-documentation-standards.md +31 -0
  96. package/docs/standards/9-operations-standards.md +19 -0
  97. package/docs/standards/README.md +20 -201
  98. package/docs/testing/test-setup-for-consumers.md +2 -0
  99. package/docs/troubleshooting/common-issues.md +17 -1
  100. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  101. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  102. package/eslint-config-pace-core.cjs +20 -0
  103. package/package.json +14 -20
  104. package/scripts/{build-docs-incremental.js → build-docs.js} +3 -2
  105. package/scripts/setup.cjs +536 -0
  106. package/scripts/validate.cjs +480 -0
  107. package/src/__tests__/helpers/{__tests__/component-test-utils.test.tsx → component-test-utils.test.tsx} +3 -3
  108. package/src/__tests__/helpers/{__tests__/optimized-test-setup.test.ts → optimized-test-setup.test.ts} +2 -2
  109. package/src/__tests__/helpers/{__tests__/supabaseMock.test.ts → supabaseMock.test.ts} +2 -2
  110. package/src/__tests__/helpers/{__tests__/test-providers.test.tsx → test-providers.test.tsx} +1 -1
  111. package/src/__tests__/helpers/test-providers.tsx +37 -39
  112. package/src/__tests__/helpers/{__tests__/test-utils.test.tsx → test-utils.test.tsx} +4 -3
  113. package/src/__tests__/helpers/{__tests__/timer-utils.test.ts → timer-utils.test.ts} +2 -2
  114. package/src/assets/app-icons/index.test.ts +304 -0
  115. package/src/components/AddressField/AddressField.test.tsx +1 -1
  116. package/src/components/AddressField/AddressField.tsx +238 -212
  117. package/src/components/Button/Button.tsx +1 -1
  118. package/src/components/Card/Card.test.tsx +172 -17
  119. package/src/components/Card/Card.tsx +19 -10
  120. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  121. package/src/components/ContextSelector/{__tests__/ContextSelector.test.tsx → ContextSelector.test.tsx} +6 -6
  122. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  123. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  124. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  125. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  126. package/src/components/DataTable/{__tests__/DataTable.comprehensive.test.tsx → DataTable.comprehensive.test.tsx} +6 -6
  127. package/src/components/DataTable/{__tests__/DataTable.default-state.test.tsx → DataTable.default-state.test.tsx} +5 -5
  128. package/src/components/DataTable/{__tests__/DataTable.export.test.tsx → DataTable.export.test.tsx} +10 -10
  129. package/src/components/DataTable/{__tests__/DataTable.grouping-aggregation.test.tsx → DataTable.grouping-aggregation.test.tsx} +6 -6
  130. package/src/components/DataTable/{__tests__/DataTable.hooks.test.tsx → DataTable.hooks.test.tsx} +6 -6
  131. package/src/components/DataTable/{__tests__/DataTable.select-label-display.test.tsx → DataTable.select-label-display.test.tsx} +6 -6
  132. package/src/components/DataTable/DataTable.test.tsx +787 -416
  133. package/src/components/DataTable/DataTable.tsx +12 -12
  134. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  135. package/src/components/DataTable/{__tests__/DataTableCore.test-setup.ts → DataTableCore.test-setup.ts} +10 -9
  136. package/src/components/DataTable/{__tests__/DataTableCore.test.tsx → DataTableCore.test.tsx} +8 -8
  137. package/src/components/DataTable/{__tests__/README.md → README.md} +17 -7
  138. package/src/components/DataTable/TESTING.md +101 -0
  139. package/src/components/DataTable/{__tests__/a11y.basic.test.tsx → a11y.basic.test.tsx} +34 -34
  140. package/src/components/DataTable/components/DataTableCore.tsx +104 -864
  141. package/src/components/DataTable/components/{__tests__/GroupingDropdown.test.tsx → GroupingDropdown.test.tsx} +17 -8
  142. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +61 -559
  144. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  145. package/src/components/DataTable/context/{__tests__/DataTableContext.test.tsx → DataTableContext.test.tsx} +2 -2
  146. package/src/components/DataTable/context/DataTableContext.tsx +7 -6
  147. package/src/components/DataTable/core/{__tests__/ColumnFactory.test.ts → ColumnFactory.test.ts} +2 -2
  148. package/src/components/DataTable/hooks/{__tests__/useColumnOrderPersistence.test.ts → useColumnOrderPersistence.test.ts} +2 -2
  149. package/src/components/DataTable/hooks/{__tests__/useColumnVisibilityPersistence.test.ts → useColumnVisibilityPersistence.test.ts} +2 -2
  150. package/src/components/DataTable/hooks/{__tests__/useDataTableConfiguration.test.ts → useDataTableConfiguration.test.ts} +3 -3
  151. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
  152. package/src/components/DataTable/hooks/{__tests__/useDataTableDataPipeline.test.ts → useDataTableDataPipeline.test.ts} +6 -6
  153. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  154. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  155. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  156. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +238 -0
  157. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  158. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  159. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  160. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  161. package/src/components/DataTable/hooks/{__tests__/useDataTablePermissions.test.ts → useDataTablePermissions.test.ts} +11 -11
  162. package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
  163. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  164. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  165. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  166. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  167. package/src/components/DataTable/hooks/useDataTableScope.test.ts +110 -0
  168. package/src/components/DataTable/hooks/useDataTableScope.ts +123 -0
  169. package/src/components/DataTable/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +47 -5
  170. package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
  171. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  172. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  173. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  174. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  175. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  176. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  177. package/src/components/DataTable/hooks/{__tests__/useEffectiveColumnOrder.test.ts → useEffectiveColumnOrder.test.ts} +2 -2
  178. package/src/components/DataTable/hooks/{__tests__/useHierarchicalState.test.ts → useHierarchicalState.test.ts} +2 -2
  179. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.test.ts +3 -3
  180. package/src/components/DataTable/{components/hooks → hooks}/useImportModalFocus.ts +2 -2
  181. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  182. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  183. package/src/components/DataTable/hooks/{__tests__/useKeyboardNavigation.test.ts → useKeyboardNavigation.test.ts} +3 -3
  184. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
  185. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.test.ts +3 -3
  186. package/src/components/DataTable/{components/hooks → hooks}/usePermissionTracking.ts +3 -3
  187. package/src/components/DataTable/hooks/{__tests__/useServerSideDataEffect.test.ts → useServerSideDataEffect.test.ts} +2 -2
  188. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
  189. package/src/components/DataTable/hooks/{__tests__/useTableColumns.test.ts → useTableColumns.test.ts} +2 -2
  190. package/src/components/DataTable/hooks/{__tests__/useTableHandlers.test.ts → useTableHandlers.test.ts} +25 -4
  191. package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
  192. package/src/components/DataTable/index.ts +18 -17
  193. package/src/components/DataTable/{__tests__/keyboard.test.tsx → keyboard.test.tsx} +41 -63
  194. package/src/components/DataTable/{__tests__/mocks → mocks}/MockRBACProvider.tsx +1 -1
  195. package/src/components/DataTable/{__tests__/pagination.modes.test.tsx → pagination.modes.test.tsx} +6 -6
  196. package/src/components/DataTable/{__tests__/ssr.strict-mode.test.tsx → ssr.strict-mode.test.tsx} +2 -2
  197. package/src/components/DataTable/{__tests__/styles.test.ts → styles.test.ts} +1 -4
  198. package/src/components/DataTable/styles.ts +0 -1
  199. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  200. package/src/components/DataTable/{__tests__/test-utils → test-utils}/dataFactories.ts +2 -2
  201. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  202. package/src/components/DataTable/{__tests__/test-utils/sharedTestUtils.tsx → test-utils/sharedTestUtils.ts} +97 -66
  203. package/src/components/DataTable/{__tests__/test-utils.ts → test-utils.ts} +1 -1
  204. package/src/components/DataTable/types/actions.ts +71 -0
  205. package/src/components/DataTable/types/base.ts +39 -0
  206. package/src/components/DataTable/types/columns.ts +125 -0
  207. package/src/components/DataTable/types/export.ts +32 -0
  208. package/src/components/DataTable/types/features.ts +81 -0
  209. package/src/components/DataTable/types/hierarchical.ts +44 -0
  210. package/src/components/DataTable/types/index.ts +43 -0
  211. package/src/components/DataTable/types/pagination.ts +85 -0
  212. package/src/components/DataTable/types/performance.ts +47 -0
  213. package/src/components/DataTable/types/props.ts +62 -0
  214. package/src/components/DataTable/types/rbac.ts +45 -0
  215. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableCore.test.tsx +430 -28
  216. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  217. package/src/components/DataTable/{components/__tests__ → ui/layout}/DataTableErrorBoundary.test.tsx +4 -4
  218. package/src/components/DataTable/{components → ui/layout}/DataTableErrorBoundary.tsx +7 -7
  219. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  220. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  221. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  222. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  223. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  224. package/src/components/DataTable/{components → ui/modals}/DataTableModals.tsx +36 -28
  225. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  226. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  227. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  228. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  229. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  230. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  231. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  232. package/src/components/DataTable/{components/__tests__ → ui/shared}/AccessDeniedPage.test.tsx +2 -2
  233. package/src/components/DataTable/{components → ui/shared}/AccessDeniedPage.tsx +2 -2
  234. package/src/components/DataTable/{components/__tests__ → ui/shared}/ActionButtons.test.tsx +6 -4
  235. package/src/components/DataTable/{components → ui/shared}/ActionButtons.tsx +4 -4
  236. package/src/components/DataTable/{components/__tests__ → ui/shared}/ColumnFilter.test.tsx +29 -16
  237. package/src/components/DataTable/{components → ui/shared}/ColumnFilter.tsx +4 -4
  238. package/src/components/DataTable/{components/__tests__ → ui/shared}/PaginationControls.test.tsx +38 -16
  239. package/src/components/DataTable/{components → ui/shared}/PaginationControls.tsx +21 -15
  240. package/src/components/DataTable/{components/__tests__ → ui/shared}/SortIndicator.test.tsx +2 -2
  241. package/src/components/DataTable/{components → ui/shared}/SortIndicator.tsx +1 -1
  242. package/src/components/DataTable/{components/__tests__ → ui/table}/EditFields.test.tsx +3 -3
  243. package/src/components/DataTable/{components → ui/table}/EditFields.tsx +138 -69
  244. package/src/components/DataTable/{components/__tests__ → ui/table}/EditableRow.test.tsx +36 -27
  245. package/src/components/DataTable/{components → ui/table}/EditableRow.tsx +86 -104
  246. package/src/components/DataTable/{components/__tests__ → ui/table}/EmptyState.test.tsx +2 -62
  247. package/src/components/DataTable/{components → ui/table}/EmptyState.tsx +7 -15
  248. package/src/components/DataTable/{components/__tests__ → ui/table}/FilterRow.test.tsx +5 -4
  249. package/src/components/DataTable/{components → ui/table}/FilterRow.tsx +3 -3
  250. package/src/components/DataTable/{components/__tests__ → ui/table}/LoadingState.test.tsx +6 -10
  251. package/src/components/DataTable/{components → ui/table}/LoadingState.tsx +4 -4
  252. package/src/components/DataTable/{components/__tests__ → ui/table}/RowComponent.test.tsx +412 -17
  253. package/src/components/DataTable/{components → ui/table}/RowComponent.tsx +183 -177
  254. package/src/components/DataTable/{components/__tests__ → ui/table}/UnifiedTableBody.test.tsx +425 -16
  255. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  256. package/src/components/DataTable/{components/__tests__ → ui/table}/cellValueUtils.test.ts +2 -2
  257. package/src/components/DataTable/{components → ui/table}/cellValueUtils.ts +1 -1
  258. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/BulkOperationsDropdown.test.tsx +12 -5
  259. package/src/components/DataTable/{components → ui/toolbar}/BulkOperationsDropdown.tsx +3 -3
  260. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/ColumnVisibilityDropdown.test.tsx +7 -4
  261. package/src/components/DataTable/{components → ui/toolbar}/ColumnVisibilityDropdown.tsx +7 -7
  262. package/src/components/DataTable/{components/__tests__ → ui/toolbar}/DataTableToolbar.test.tsx +4 -4
  263. package/src/components/DataTable/{components → ui/toolbar}/DataTableToolbar.tsx +4 -4
  264. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  265. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  266. package/src/components/DataTable/utils/{__tests__/a11yUtils.test.ts → a11yUtils.test.ts} +2 -2
  267. package/src/components/DataTable/utils/{__tests__/aggregationUtils.test.ts → aggregationUtils.test.ts} +3 -3
  268. package/src/components/DataTable/utils/{__tests__/columnUtils.test.ts → columnUtils.test.ts} +2 -2
  269. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  270. package/src/components/DataTable/utils/csvParse.ts +65 -0
  271. package/src/components/DataTable/utils/{__tests__/errorHandling.test.ts → errorHandling.test.ts} +2 -2
  272. package/src/components/DataTable/utils/{__tests__/exportUtils.test.ts → exportUtils.test.ts} +3 -3
  273. package/src/components/DataTable/utils/{__tests__/flexibleImport.test.ts → flexibleImport.test.ts} +2 -2
  274. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  275. package/src/components/DataTable/utils/{__tests__/hierarchicalSorting.test.ts → hierarchicalSorting.test.ts} +3 -3
  276. package/src/components/DataTable/utils/{__tests__/hierarchicalUtils.test.ts → hierarchicalUtils.test.ts} +3 -3
  277. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  278. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  279. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  280. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  281. package/src/components/DataTable/utils/{__tests__/paginationUtils.test.ts → paginationUtils.test.ts} +2 -2
  282. package/src/components/DataTable/utils/paginationUtils.ts +6 -3
  283. package/src/components/DataTable/utils/{__tests__/performanceUtils.test.ts → performanceUtils.test.ts} +3 -3
  284. package/src/components/DataTable/utils/{__tests__/rowUtils.test.ts → rowUtils.test.ts} +3 -3
  285. package/src/components/DataTable/utils/{__tests__/selectFieldUtils.test.ts → selectFieldUtils.test.ts} +66 -3
  286. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
  287. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  288. package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
  289. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  290. package/src/components/Dialog/Dialog.test.tsx +896 -89
  291. package/src/components/Dialog/Dialog.tsx +174 -882
  292. package/src/components/Dialog/dialogLock.test.ts +238 -0
  293. package/src/components/Dialog/dialogLock.ts +98 -0
  294. package/src/components/Dialog/index.ts +2 -0
  295. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  296. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  297. package/src/components/Dialog/useDialogLifecycle.test.ts +358 -0
  298. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  299. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  300. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  301. package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
  302. package/src/components/FileDisplay/FileDisplay.tsx +24 -656
  303. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  304. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  305. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  306. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  307. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  308. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  309. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  310. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  311. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  312. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  313. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  314. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  315. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  316. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  317. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  318. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  319. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  320. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  321. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  322. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  323. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  324. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  325. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  326. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  327. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  328. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  329. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.test.ts +40 -42
  330. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  331. package/src/{hooks/__tests__ → components/FileDisplay}/useFileDisplay.unit.test.ts +406 -77
  332. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  333. package/src/{hooks/public → components/FileDisplay}/usePublicFileDisplay.test.ts +94 -88
  334. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  335. package/src/components/FileUpload/FileUpload.test.tsx +16 -10
  336. package/src/components/FileUpload/FileUpload.tsx +107 -525
  337. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  338. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  339. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  340. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  341. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  342. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  343. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  344. package/src/components/Footer/Footer.test.tsx +6 -292
  345. package/src/components/Footer/Footer.tsx +8 -125
  346. package/src/components/Form/Form.test.tsx +44 -27
  347. package/src/components/Form/Form.tsx +64 -287
  348. package/src/components/Form/useFormPersistence.ts +257 -0
  349. package/src/components/Header/Header.test.tsx +17 -18
  350. package/src/components/Header/Header.tsx +10 -1
  351. package/src/components/Input/Input.tsx +1 -1
  352. package/src/components/Label/Label.test.tsx +1 -1
  353. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
  354. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  355. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
  356. package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
  357. package/src/components/NavigationMenu/index.ts +6 -1
  358. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  359. package/src/components/NavigationMenu/{__tests__/useNavigationFiltering.test.ts → useNavigationFiltering.test.ts} +68 -53
  360. package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
  361. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  362. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +77 -62
  363. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
  364. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
  365. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
  366. package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
  367. package/src/components/PaceAppLayout/useFilteredNavItems.ts +304 -0
  368. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +142 -0
  369. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  370. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  371. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +79 -0
  372. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  373. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  374. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
  375. package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
  376. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  377. package/src/components/Progress/Progress.tsx +1 -2
  378. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
  379. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  380. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  381. package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
  382. package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
  383. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
  384. package/src/components/Select/Select.test.tsx +1 -1
  385. package/src/components/Select/Select.tsx +28 -18
  386. package/src/components/Select/{__tests__/context.test.tsx → context.test.tsx} +3 -3
  387. package/src/components/Select/{utils/__tests__/text.test.tsx → text.test.tsx} +2 -2
  388. package/src/components/Select/{utils/text.ts → text.ts} +1 -1
  389. package/src/components/Select/{hooks/__tests__/useSelectEvents.test.ts → useSelectEvents.test.ts} +5 -5
  390. package/src/components/Select/{hooks/useSelectEvents.ts → useSelectEvents.ts} +2 -2
  391. package/src/components/Select/{hooks/__tests__/useSelectSearch.test.tsx → useSelectSearch.test.tsx} +7 -7
  392. package/src/components/Select/{hooks/useSelectSearch.ts → useSelectSearch.ts} +2 -2
  393. package/src/components/Select/{hooks/__tests__/useSelectState.test.ts → useSelectState.test.ts} +16 -2
  394. package/src/components/Select/{hooks/useSelectState.ts → useSelectState.ts} +3 -3
  395. package/src/components/Table/Table.test.tsx +348 -0
  396. package/src/components/Tabs/Tabs.test.tsx +270 -0
  397. package/src/components/Tabs/Tabs.tsx +1 -1
  398. package/src/components/Toast/Toast.test.tsx +420 -0
  399. package/src/components/{__tests__/index.test.ts → index.test.ts} +2 -2
  400. package/src/constants/{__tests__/performance.test.ts → performance.test.ts} +2 -2
  401. package/src/hooks/{__tests__/ServiceHooks.test.tsx → ServiceHooks.test.tsx} +8 -8
  402. package/src/hooks/{__tests__/hooks.integration.test.tsx → hooks.integration.test.tsx} +11 -11
  403. package/src/hooks/index.ts +7 -4
  404. package/src/hooks/{__tests__/index.unit.test.ts → index.unit.test.ts} +2 -2
  405. package/src/hooks/public/usePublicEvent.test.ts +1 -1
  406. package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
  407. package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
  408. package/src/hooks/services/useAuth.ts +9 -7
  409. package/src/hooks/useAddressAutocomplete.test.ts +22 -22
  410. package/src/hooks/useAddressAutocomplete.ts +90 -75
  411. package/src/hooks/{__tests__/useAppConfig.unit.test.ts → useAppConfig.unit.test.ts} +328 -22
  412. package/src/hooks/{__tests__/useComponentPerformance.unit.test.tsx → useComponentPerformance.unit.test.tsx} +27 -41
  413. package/src/hooks/useDataTablePerformance.ts +100 -120
  414. package/src/hooks/{__tests__/useDataTablePerformance.unit.test.ts → useDataTablePerformance.unit.test.ts} +5 -5
  415. package/src/hooks/{__tests__/useDataTableState.test.ts → useDataTableState.test.ts} +2 -2
  416. package/src/hooks/{__tests__/useDebounce.unit.test.ts → useDebounce.unit.test.ts} +2 -2
  417. package/src/hooks/useEventTheme.test.ts +4 -1
  418. package/src/hooks/useEventTheme.ts +49 -21
  419. package/src/hooks/useEvents.ts +41 -1
  420. package/src/hooks/{__tests__/useEvents.unit.test.ts → useEvents.unit.test.ts} +5 -5
  421. package/src/hooks/useFileReference.test.ts +44 -41
  422. package/src/hooks/useFileReference.ts +182 -173
  423. package/src/hooks/useFileUrl.ts +1 -1
  424. package/src/hooks/{__tests__/useFileUrl.unit.test.ts → useFileUrl.unit.test.ts} +26 -36
  425. package/src/hooks/{__tests__/useFileUrlCache.test.ts → useFileUrlCache.test.ts} +8 -8
  426. package/src/hooks/useFileUrlCache.ts +1 -1
  427. package/src/hooks/{__tests__/useFocusManagement.unit.test.ts → useFocusManagement.unit.test.ts} +2 -2
  428. package/src/hooks/{__tests__/useFocusTrap.unit.test.tsx → useFocusTrap.unit.test.tsx} +2 -2
  429. package/src/hooks/{__tests__/useFormDialog.test.ts → useFormDialog.test.ts} +2 -2
  430. package/src/hooks/useInactivityTracker.ts +138 -131
  431. package/src/hooks/{__tests__/useInactivityTracker.unit.test.ts → useInactivityTracker.unit.test.ts} +3 -3
  432. package/src/hooks/{__tests__/useIsMobile.unit.test.ts → useIsMobile.unit.test.ts} +2 -2
  433. package/src/hooks/useIsPrint.ts +62 -0
  434. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  435. package/src/hooks/{__tests__/useKeyboardShortcuts.unit.test.ts → useKeyboardShortcuts.unit.test.ts} +2 -2
  436. package/src/hooks/{__tests__/useOrganisationPermissions.unit.test.tsx → useOrganisationPermissions.unit.test.tsx} +4 -4
  437. package/src/hooks/useOrganisationSecurity.test.ts +3 -3
  438. package/src/hooks/useOrganisationSecurity.ts +190 -201
  439. package/src/hooks/{__tests__/useOrganisationSecurity.unit.test.tsx → useOrganisationSecurity.unit.test.tsx} +61 -63
  440. package/src/hooks/{__tests__/useOrganisations.unit.test.ts → useOrganisations.unit.test.ts} +5 -5
  441. package/src/hooks/{__tests__/usePerformanceMonitor.unit.test.ts → usePerformanceMonitor.unit.test.ts} +13 -14
  442. package/src/hooks/{__tests__/usePermissionCache.test.ts → usePermissionCache.test.ts} +26 -27
  443. package/src/hooks/usePermissionCache.ts +276 -271
  444. package/src/hooks/{__tests__/usePreventTabReload.test.ts → usePreventTabReload.test.ts} +2 -2
  445. package/src/hooks/{__tests__/usePublicEvent.simple.test.ts → usePublicEvent.simple.test.ts} +4 -4
  446. package/src/hooks/{__tests__/usePublicEvent.test.ts → usePublicEvent.test.ts} +4 -4
  447. package/src/hooks/{__tests__/usePublicEvent.unit.test.ts → usePublicEvent.unit.test.ts} +4 -4
  448. package/src/hooks/{__tests__/usePublicFileDisplay.test.ts → usePublicFileDisplay.test.ts} +12 -12
  449. package/src/hooks/{__tests__/usePublicRouteParams.unit.test.ts → usePublicRouteParams.unit.test.ts} +3 -3
  450. package/src/hooks/{__tests__/useQueryCache.test.ts → useQueryCache.test.ts} +2 -2
  451. package/src/hooks/useQueryCache.ts +0 -2
  452. package/src/hooks/{__tests__/useRBAC.unit.test.ts → useRBAC.unit.test.ts} +55 -38
  453. package/src/hooks/{__tests__/useSessionDraft.test.ts → useSessionDraft.test.ts} +2 -2
  454. package/src/hooks/{__tests__/useSessionRestoration.unit.test.tsx → useSessionRestoration.unit.test.tsx} +10 -19
  455. package/src/hooks/useStorage.ts +21 -16
  456. package/src/hooks/{__tests__/useStorage.unit.test.ts → useStorage.unit.test.ts} +38 -75
  457. package/src/hooks/{__tests__/useToast.test.ts → useToast.test.ts} +2 -2
  458. package/src/hooks/{__tests__/useToast.unit.test.tsx → useToast.unit.test.tsx} +2 -2
  459. package/src/hooks/{__tests__/useZodForm.unit.test.tsx → useZodForm.unit.test.tsx} +2 -2
  460. package/src/icons/{__tests__/index.test.ts → index.test.ts} +2 -2
  461. package/src/icons/index.ts +2 -0
  462. package/src/{__tests__/index.test.ts → index.test.ts} +3 -7
  463. package/src/index.ts +15 -7
  464. package/src/providers/{__tests__/AuthProvider.test.tsx → AuthProvider.test.tsx} +3 -3
  465. package/src/providers/{__tests__/EventProvider.test.tsx → EventProvider.test.tsx} +3 -3
  466. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  467. package/src/providers/{__tests__/InactivityProvider.test.tsx → InactivityProvider.test.tsx} +14 -21
  468. package/src/providers/{__tests__/ProviderLifecycle.test.tsx → ProviderLifecycle.test.tsx} +4 -4
  469. package/src/providers/{__tests__/UnifiedAuthProvider.test.tsx → UnifiedAuthProvider.test.tsx} +1 -1
  470. package/src/providers/{__tests__/index.test.ts → index.test.ts} +2 -2
  471. package/src/providers/services/{__tests__/AuthServiceProvider.integration.test.tsx → AuthServiceProvider.integration.test.tsx} +4 -4
  472. package/src/providers/services/{__tests__/AuthServiceProvider.test.tsx → AuthServiceProvider.test.tsx} +7 -7
  473. package/src/providers/services/{__tests__/EventServiceProvider.test.tsx → EventServiceProvider.test.tsx} +7 -7
  474. package/src/providers/services/{__tests__/InactivityServiceProvider.test.tsx → InactivityServiceProvider.test.tsx} +5 -5
  475. package/src/providers/services/{__tests__/OrganisationServiceProvider.test.tsx → OrganisationServiceProvider.test.tsx} +6 -6
  476. package/src/providers/services/UnifiedAuthContext.ts +30 -27
  477. package/src/providers/services/{__tests__/UnifiedAuthProvider.advanced.test.tsx → UnifiedAuthProvider.advanced.test.tsx} +8 -9
  478. package/src/providers/services/{__tests__/UnifiedAuthProvider.appId.test.tsx → UnifiedAuthProvider.appId.test.tsx} +25 -25
  479. package/src/providers/services/{__tests__/UnifiedAuthProvider.integration.test.tsx → UnifiedAuthProvider.integration.test.tsx} +14 -11
  480. package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
  481. package/src/providers/services/{__tests__/contexts.test.tsx → contexts.test.tsx} +6 -6
  482. package/src/providers/services/{__tests__/useUnifiedAuth.test.tsx → useUnifiedAuth.test.tsx} +6 -6
  483. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  484. package/src/providers/useInactivity.test-helper.ts +27 -0
  485. package/src/rbac/{__tests__/adapters.comprehensive.test.tsx → adapters.comprehensive.test.tsx} +24 -24
  486. package/src/rbac/adapters.test.tsx +22 -22
  487. package/src/rbac/adapters.tsx +29 -29
  488. package/src/rbac/api.test.ts +973 -42
  489. package/src/rbac/api.ts +228 -253
  490. package/src/rbac/{__tests__/audit-batched.test.ts → audit-batched.test.ts} +6 -6
  491. package/src/rbac/audit.ts +4 -1
  492. package/src/rbac/{__tests__/auth-rbac-security.integration.test.tsx → auth-rbac-security.integration.test.tsx} +1 -1
  493. package/src/rbac/{__tests__/auth-rbac.e2e.test.tsx → auth-rbac.e2e.test.tsx} +27 -34
  494. package/src/rbac/cache-invalidation.test.ts +715 -0
  495. package/src/rbac/components/{__tests__/AccessDenied.test.tsx → AccessDenied.test.tsx} +3 -3
  496. package/src/rbac/components/{__tests__/NavigationGuard.test.tsx → NavigationGuard.test.tsx} +13 -11
  497. package/src/{__tests__/rbac/PagePermissionGuard.test.tsx → rbac/components/PagePermissionGuard.guard.test.tsx} +33 -19
  498. package/src/rbac/components/{__tests__/PagePermissionGuard.performance.test.tsx → PagePermissionGuard.performance.test.tsx} +30 -9
  499. package/src/rbac/components/{__tests__/PagePermissionGuard.race-condition.test.tsx → PagePermissionGuard.race-condition.test.tsx} +7 -7
  500. package/src/rbac/components/{__tests__/PagePermissionGuard.test.tsx → PagePermissionGuard.test.tsx} +10 -10
  501. package/src/rbac/components/PagePermissionGuard.tsx +177 -372
  502. package/src/rbac/components/{__tests__/PagePermissionGuard.verification.test.tsx → PagePermissionGuard.verification.test.tsx} +7 -7
  503. package/src/rbac/config.ts +58 -18
  504. package/src/rbac/{__tests__/engine.comprehensive.test.ts → engine.comprehensive.test.ts} +3 -3
  505. package/src/rbac/engine.test.ts +494 -0
  506. package/src/rbac/errors.ts +89 -55
  507. package/src/rbac/hooks/permissions/runPermissionCheck.ts +77 -0
  508. package/src/rbac/hooks/permissions/{__tests__/useAccessLevel.test.ts → useAccessLevel.test.ts} +40 -40
  509. package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
  510. package/src/rbac/hooks/permissions/{__tests__/useCan.test.ts → useCan.test.ts} +41 -41
  511. package/src/rbac/hooks/permissions/useCan.ts +170 -252
  512. package/src/rbac/hooks/permissions/{__tests__/useMultiplePermissions.test.ts → useMultiplePermissions.test.ts} +49 -49
  513. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +6 -2
  514. package/src/rbac/hooks/permissions/{__tests__/usePermissions.test.ts → usePermissions.test.ts} +10 -12
  515. package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
  516. package/src/rbac/hooks/useCan.test.ts +42 -42
  517. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  518. package/src/rbac/hooks/usePageGuardScope.ts +117 -0
  519. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  520. package/src/rbac/hooks/{__tests__/usePermissions.integration.test.ts → usePermissions.integration.test.ts} +9 -9
  521. package/src/{__tests__/hooks/usePermissions.test.ts → rbac/hooks/usePermissions.stability.test.ts} +18 -18
  522. package/src/rbac/hooks/usePermissions.test.ts +54 -54
  523. package/src/rbac/hooks/useRBAC.test.ts +313 -217
  524. package/src/rbac/hooks/useRBAC.ts +145 -81
  525. package/src/rbac/hooks/useResourcePermissions.test.ts +25 -25
  526. package/src/rbac/hooks/useResourcePermissions.ts +68 -134
  527. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  528. package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
  529. package/src/rbac/hooks/useRoleManagement.ts +153 -585
  530. package/src/rbac/hooks/{__tests__/useSecureSupabase.test.ts → useSecureSupabase.test.ts} +17 -17
  531. package/src/rbac/hooks/useSecureSupabase.ts +10 -2
  532. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  533. package/src/rbac/{__tests__/performance.test.ts → performance.test.ts} +1 -1
  534. package/src/rbac/{__tests__/rbac-core.test.tsx → rbac-core.test.tsx} +3 -3
  535. package/src/rbac/{__tests__/rbac-engine-core-logic.test.ts → rbac-engine-core-logic.test.ts} +2 -2
  536. package/src/rbac/{__tests__/rbac-engine-simplified.test.ts → rbac-engine-simplified.test.ts} +3 -3
  537. package/src/rbac/{__tests__/rbac-functions.test.ts → rbac-functions.test.ts} +57 -0
  538. package/src/rbac/{__tests__/rbac-role-isolation.test.ts → rbac-role-isolation.test.ts} +2 -2
  539. package/src/rbac/request-deduplication.test.ts +14 -9
  540. package/src/rbac/request-deduplication.ts +5 -4
  541. package/src/rbac/{__tests__/scenarios.user-role.test.tsx → scenarios.user-role.test.tsx} +23 -23
  542. package/src/rbac/secureClient.test.ts +514 -83
  543. package/src/rbac/secureClient.ts +8 -2
  544. package/src/rbac/security.test.ts +323 -0
  545. package/src/rbac/types/roleManagement.ts +66 -0
  546. package/src/rbac/utils/{__tests__/clientSecurity.test.ts → clientSecurity.test.ts} +4 -4
  547. package/src/rbac/utils/{__tests__/contextValidator.test.ts → contextValidator.test.ts} +4 -4
  548. package/src/rbac/utils/contextValidator.ts +5 -1
  549. package/src/rbac/utils/{__tests__/deep-equal.test.ts → deep-equal.test.ts} +1 -1
  550. package/src/rbac/utils/{__tests__/eventContext.test.ts → eventContext.test.ts} +36 -21
  551. package/src/rbac/utils/eventContext.ts +37 -33
  552. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  553. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  554. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  555. package/src/services/{__tests__/AuthService.edge-cases.test.ts → AuthService.edge-cases.test.ts} +19 -19
  556. package/src/services/{__tests__/AuthService.restoreSession.test.ts → AuthService.restoreSession.test.ts} +2 -2
  557. package/src/services/{__tests__/AuthService.test.ts → AuthService.test.ts} +89 -55
  558. package/src/services/AuthService.ts +184 -205
  559. package/src/services/{__tests__/BaseService.edge-cases.test.ts → BaseService.edge-cases.test.ts} +3 -3
  560. package/src/services/{__tests__/BaseService.test.ts → BaseService.test.ts} +2 -2
  561. package/src/services/{__tests__/EventService.edge-cases.test.ts → EventService.edge-cases.test.ts} +27 -24
  562. package/src/services/{__tests__/EventService.eventColours.test.ts → EventService.eventColours.test.ts} +1 -1
  563. package/src/services/{__tests__/EventService.test.ts → EventService.test.ts} +256 -24
  564. package/src/services/EventService.ts +242 -312
  565. package/src/services/{__tests__/InactivityService.edge-cases.test.ts → InactivityService.edge-cases.test.ts} +3 -3
  566. package/src/services/{__tests__/InactivityService.lifecycle.test.ts → InactivityService.lifecycle.test.ts} +2 -2
  567. package/src/services/{__tests__/InactivityService.test.ts → InactivityService.test.ts} +179 -4
  568. package/src/services/InactivityService.ts +172 -213
  569. package/src/services/{__tests__/OrganisationService.edge-cases.test.ts → OrganisationService.edge-cases.test.ts} +5 -5
  570. package/src/services/{__tests__/OrganisationService.pagination.test.ts → OrganisationService.pagination.test.ts} +4 -4
  571. package/src/services/{__tests__/OrganisationService.test.ts → OrganisationService.test.ts} +410 -7
  572. package/src/services/OrganisationService.ts +184 -238
  573. package/src/services/base/BaseService.test.ts +1 -1
  574. package/src/services/interfaces/{__tests__/IAuthService.test.ts → IAuthService.test.ts} +21 -27
  575. package/src/services/interfaces/IAuthService.ts +10 -9
  576. package/src/services/interfaces/{__tests__/IEventService.test.ts → IEventService.test.ts} +4 -4
  577. package/src/services/interfaces/{__tests__/IInactivityService.test.ts → IInactivityService.test.ts} +3 -3
  578. package/src/services/interfaces/{__tests__/IOrganisationService.test.ts → IOrganisationService.test.ts} +3 -3
  579. package/src/styles/core.css +243 -12
  580. package/src/theming/{__tests__/parseEventColours.test.ts → parseEventColours.test.ts} +1 -1
  581. package/src/theming/{__tests__/runtime.test.ts → runtime.test.ts} +8 -17
  582. package/src/theming/runtime.ts +71 -2
  583. package/src/types/api-result.ts +53 -0
  584. package/src/types/{__tests__/core.test.ts → core.test.ts} +2 -2
  585. package/src/types/{__tests__/database-generated.test.ts → database-generated.test.ts} +3 -3
  586. package/src/types/database.generated.ts +45 -10
  587. package/src/types/event.ts +38 -18
  588. package/src/types/{__tests__/file-reference.test.ts → file-reference.test.ts} +13 -13
  589. package/src/types/file-reference.ts +37 -12
  590. package/src/types/{__tests__/guards.test.ts → guards.test.ts} +2 -2
  591. package/src/types/{__tests__/index.test.ts → index.test.ts} +2 -2
  592. package/src/types/index.ts +3 -0
  593. package/src/types/{__tests__/organisation.roles.test.ts → organisation.roles.test.ts} +1 -1
  594. package/src/types/{__tests__/organisation.test.ts → organisation.test.ts} +3 -31
  595. package/src/types/organisation.ts +15 -15
  596. package/src/types/supabase.ts +13 -4
  597. package/src/types/{__tests__/theme.test.ts → theme.test.ts} +1 -1
  598. package/src/types/{__tests__/type-validation.test.ts → type-validation.test.ts} +1 -1
  599. package/src/types/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  600. package/src/utils/app/appIdResolver.test.ts +98 -71
  601. package/src/utils/app/appIdResolver.ts +31 -20
  602. package/src/utils/{__tests__/appConfig.unit.test.ts → appConfig.unit.test.ts} +1 -1
  603. package/src/utils/{__tests__/audit.unit.test.ts → audit.unit.test.ts} +1 -1
  604. package/src/utils/{__tests__/auth-utils.unit.test.ts → auth-utils.unit.test.ts} +16 -17
  605. package/src/utils/{__tests__/bundleAnalysis.unit.test.ts → bundleAnalysis.unit.test.ts} +35 -35
  606. package/src/utils/{__tests__/cn.unit.test.ts → cn.unit.test.ts} +1 -1
  607. package/src/utils/context/organisationContext.test.ts +105 -91
  608. package/src/utils/context/organisationContext.ts +29 -40
  609. package/src/utils/core/{__tests__/cn.test.ts → cn.test.ts} +3 -3
  610. package/src/utils/core/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +2 -2
  611. package/src/utils/core/{__tests__/logger.test.ts → logger.test.ts} +2 -2
  612. package/src/utils/core/mergeRefs.ts +24 -0
  613. package/src/utils/{__tests__/debugLogger.test.ts → debugLogger.test.ts} +1 -1
  614. package/src/utils/{__tests__/deviceFingerprint.unit.test.ts → deviceFingerprint.unit.test.ts} +1 -1
  615. package/src/utils/dynamic/createLazyComponent.tsx +9 -1
  616. package/src/utils/dynamic/{__tests__/dynamicUtils.test.ts → dynamicUtils.test.ts} +2 -2
  617. package/src/utils/dynamic/{__tests__/lazyLoad.test.tsx → lazyLoad.test.tsx} +2 -2
  618. package/src/utils/{__tests__/dynamicUtils.unit.test.ts → dynamicUtils.unit.test.ts} +1 -1
  619. package/src/utils/file-reference/{__tests__/file-reference.test.ts → file-reference.test.ts} +214 -289
  620. package/src/utils/file-reference/index.ts +330 -347
  621. package/src/utils/{__tests__/formatDate.unit.test.ts → formatDate.unit.test.ts} +2 -2
  622. package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
  623. package/src/utils/formatting/formatNumber.test.ts +1 -1
  624. package/src/utils/{__tests__/formatting.unit.test.ts → formatting.unit.test.ts} +1 -1
  625. package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
  626. package/src/utils/google-places/googlePlacesUtils.ts +67 -99
  627. package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
  628. package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
  629. package/src/utils/{__tests__/index.unit.test.ts → index.unit.test.ts} +1 -1
  630. package/src/utils/{__tests__/lazyLoad.unit.test.tsx → lazyLoad.unit.test.tsx} +13 -14
  631. package/src/utils/location/location.test.ts +1 -1
  632. package/src/utils/{__tests__/logger.unit.test.ts → logger.unit.test.ts} +1 -1
  633. package/src/utils/{__tests__/organisationContext.unit.test.ts → organisationContext.unit.test.ts} +37 -48
  634. package/src/utils/performance/{__tests__/bundleAnalysis.test.ts → bundleAnalysis.test.ts} +2 -2
  635. package/src/utils/performance/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  636. package/src/utils/performance/{__tests__/performanceBudgets.test.ts → performanceBudgets.test.ts} +2 -2
  637. package/src/utils/{__tests__/performanceBenchmark.test.ts → performanceBenchmark.test.ts} +2 -2
  638. package/src/utils/{__tests__/performanceBudgets.unit.test.ts → performanceBudgets.unit.test.ts} +2 -2
  639. package/src/utils/{__tests__/permissionTypes.unit.test.ts → permissionTypes.unit.test.ts} +1 -1
  640. package/src/utils/{__tests__/permissionUtils.unit.test.ts → permissionUtils.unit.test.ts} +1 -1
  641. package/src/utils/permissions/{__tests__/permissionTypes.test.ts → permissionTypes.test.ts} +2 -2
  642. package/src/utils/persistence/{__tests__/keyDerivation.test.ts → keyDerivation.test.ts} +2 -2
  643. package/src/utils/persistence/{__tests__/sensitiveFieldDetection.test.ts → sensitiveFieldDetection.test.ts} +2 -2
  644. package/src/utils/{__tests__/request-deduplication.test.ts → request-deduplication.test.ts} +2 -2
  645. package/src/utils/{__tests__/sanitization.unit.test.ts → sanitization.unit.test.ts} +1 -1
  646. package/src/utils/{__tests__/schemaUtils.unit.test.ts → schemaUtils.unit.test.ts} +1 -1
  647. package/src/utils/{__tests__/secureDataAccess.unit.test.ts → secureDataAccess.unit.test.ts} +2 -2
  648. package/src/utils/{__tests__/secureErrors.unit.test.ts → secureErrors.unit.test.ts} +4 -4
  649. package/src/utils/{__tests__/secureStorage.unit.test.ts → secureStorage.unit.test.ts} +1 -1
  650. package/src/utils/security/auth-utils.ts +34 -23
  651. package/src/utils/security/secureDataAccess.ts +241 -281
  652. package/src/utils/security/secureErrors.test.ts +1 -1
  653. package/src/utils/security/secureStorage.test.ts +1 -1
  654. package/src/utils/security/security.test.ts +25 -17
  655. package/src/utils/security/security.ts +15 -18
  656. package/src/utils/security/securityMonitor.test.ts +1 -1
  657. package/src/utils/{__tests__/security.unit.test.ts → security.unit.test.ts} +21 -15
  658. package/src/utils/{__tests__/securityMonitor.unit.test.ts → securityMonitor.unit.test.ts} +1 -1
  659. package/src/utils/{__tests__/sessionTracking.unit.test.ts → sessionTracking.unit.test.ts} +12 -12
  660. package/src/utils/storage/{__tests__/config.unit.test.ts → config.unit.test.ts} +2 -2
  661. package/src/utils/storage/helpers.test.ts +88 -102
  662. package/src/utils/storage/helpers.ts +173 -251
  663. package/src/utils/storage/{__tests__/index.unit.test.ts → index.unit.test.ts} +3 -3
  664. package/src/utils/storage/types.ts +7 -0
  665. package/src/utils/supabase/createBaseClient.test.ts +1 -1
  666. package/src/utils/timezone/timezone.test.ts +1 -1
  667. package/src/utils/{__tests__/timezone.test.ts → timezone.test.ts} +2 -2
  668. package/src/utils/validation/{__tests__/common.test.ts → common.test.ts} +2 -2
  669. package/src/utils/validation/{__tests__/csrf.test.ts → csrf.test.ts} +56 -28
  670. package/src/utils/validation/csrf.ts +42 -41
  671. package/src/utils/validation/{__tests__/htmlSanitization.unit.test.ts → htmlSanitization.unit.test.ts} +2 -2
  672. package/src/utils/validation/{__tests__/passwordSchema.test.ts → passwordSchema.test.ts} +2 -2
  673. package/src/utils/validation/{__tests__/schema.test.ts → schema.test.ts} +2 -2
  674. package/src/utils/validation/{__tests__/sqlInjectionProtection.test.ts → sqlInjectionProtection.test.ts} +2 -2
  675. package/src/utils/validation/{__tests__/user.test.ts → user.test.ts} +2 -2
  676. package/src/utils/validation/{__tests__/validation.test.ts → validation.test.ts} +2 -2
  677. package/src/utils/validation/{__tests__/validationUtils.test.ts → validationUtils.test.ts} +2 -2
  678. package/src/utils/{__tests__/validation.unit.test.ts → validation.unit.test.ts} +1 -1
  679. package/src/utils/{__tests__/validationUtils.unit.test.ts → validationUtils.unit.test.ts} +5 -2
  680. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
  681. package/dist/chunk-KPYQWGFQ.js +0 -183
  682. package/dist/types-D05dCGma.d.ts +0 -521
  683. package/scripts/eslint-audit.cjs +0 -222
  684. package/scripts/generate-docs.js +0 -157
  685. package/scripts/install-cursor-rules.cjs +0 -255
  686. package/scripts/install-eslint-config.cjs +0 -349
  687. package/scripts/setup-build-cache.js +0 -73
  688. package/scripts/validate-pre-publish.js +0 -145
  689. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  690. package/src/__tests__/public-recipe-view.test.ts +0 -228
  691. package/src/__tests__/rls-policies.test.ts +0 -472
  692. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  693. package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
  694. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
  695. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
  696. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
  697. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
  698. package/src/components/DataTable/core/ActionManager.ts +0 -235
  699. package/src/components/DataTable/core/ColumnManager.ts +0 -204
  700. package/src/components/DataTable/core/DataManager.ts +0 -190
  701. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  702. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  703. package/src/components/DataTable/core/StateManager.ts +0 -312
  704. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
  705. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
  706. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
  707. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
  708. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
  709. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
  710. package/src/components/DataTable/core/interfaces.ts +0 -338
  711. package/src/components/DataTable/types.ts +0 -764
  712. package/src/hooks/public/usePublicFileDisplay.ts +0 -534
  713. package/src/hooks/useFileDisplay.ts +0 -748
  714. package/src/providers/OrganisationProvider.test.tsx +0 -40
  715. package/src/providers/OrganisationProvider.tsx +0 -92
  716. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  717. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
  718. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
  719. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
  720. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  721. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  722. /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
  723. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  724. /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
  725. /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
  726. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -4,15 +4,15 @@
4
4
  */
5
5
 
6
6
  import { vi } from 'vitest';
7
- import { FileReferenceServiceImpl, createFileReferenceService, uploadFileWithReference } from '../index';
8
- import { FileCategory } from '../../../types/file-reference';
9
- import { createMockSupabaseClient } from '../../../__tests__/helpers/test-utils';
7
+ import { FileReferenceServiceImpl, createFileReferenceService, uploadFileWithReference } from './index';
8
+ import { FileCategory } from '../../types/file-reference';
9
+ import { createMockSupabaseClient } from '../../__tests__/helpers/test-utils';
10
10
 
11
11
  // Mock dependencies
12
- import * as organisationContext from '../../context/organisationContext';
13
- import * as storageHelpers from '../../storage/helpers';
14
- import * as useFileDisplay from '../../../hooks/useFileDisplay';
15
- import * as rbacApi from '../../../rbac/api';
12
+ import * as organisationContext from '../context/organisationContext';
13
+ import * as storageHelpers from '../storage/helpers';
14
+ import * as useFileDisplay from '../../components/FileDisplay/useFileDisplay';
15
+ import * as rbacApi from '../../rbac/api';
16
16
 
17
17
  const mockSetOrganisationContext = vi.fn();
18
18
  const mockUploadFile = vi.fn();
@@ -29,19 +29,21 @@ beforeEach(() => {
29
29
  vi.clearAllMocks();
30
30
 
31
31
  // Default mock implementations
32
- mockSetOrganisationContext.mockResolvedValue(undefined);
32
+ mockSetOrganisationContext.mockResolvedValue({ ok: true, data: undefined });
33
33
  mockUploadFile.mockResolvedValue({
34
- success: true,
35
- path: 'org-123/documents/test.pdf',
36
- metadata: { size: 1024 }
34
+ ok: true,
35
+ data: { path: 'org-123/documents/test.pdf', metadata: { size: 1024 } }
37
36
  });
38
- mockDeleteFile.mockResolvedValue({ success: true });
37
+ mockDeleteFile.mockResolvedValue({ ok: true, data: undefined });
39
38
  mockGenerateFilePath.mockReturnValue('org-123/documents/test.pdf');
40
39
 
41
- // Default metadata extraction mock
42
- mockExtractFileMetadata.mockResolvedValue({ width: 100, height: 100 });
40
+ // Default metadata extraction mock (ApiResult)
41
+ mockExtractFileMetadata.mockResolvedValue({
42
+ ok: true,
43
+ data: { mimeType: 'application/pdf', size: 1024, appName: 'pace-core', uploadedBy: 'system', uploadedAt: new Date().toISOString(), tags: [], isPublic: false, customMetadata: {}, width: 100, height: 100 }
44
+ });
43
45
  mockGetPublicUrl.mockReturnValue('https://example.com/public-url');
44
- mockGetSignedUrl.mockResolvedValue({ url: 'https://example.com/signed-url' });
46
+ mockGetSignedUrl.mockResolvedValue({ ok: true, data: { url: 'https://example.com/signed-url', expiresAt: new Date().toISOString() } });
45
47
  mockIsSuperAdmin.mockResolvedValue(false);
46
48
 
47
49
  // Apply mocks
@@ -95,6 +97,12 @@ const createTestFile = (name = 'test.pdf', type = 'application/pdf', size = 1024
95
97
  return new File(['test content'], name, { type, size });
96
98
  };
97
99
 
100
+ /** Unwrap ApiResult for tests; asserts ok and returns data. */
101
+ function expectOk<T>(result: { ok: true; data: T } | { ok: false; error: { code: string; message: string } }): T {
102
+ expect(result.ok).toBe(true);
103
+ return (result as { ok: true; data: T }).data;
104
+ }
105
+
98
106
  describe('[service] FileReferenceServiceImpl', () => {
99
107
  let service: FileReferenceServiceImpl;
100
108
 
@@ -112,13 +120,19 @@ describe('[service] FileReferenceServiceImpl', () => {
112
120
  error: null
113
121
  });
114
122
 
123
+ mockSupabase.from.mockReturnValue({
124
+ select: vi.fn().mockReturnThis(),
125
+ eq: vi.fn().mockReturnThis(),
126
+ single: vi.fn().mockResolvedValue({ data: mockFileReference, error: null })
127
+ });
115
128
  const result = await service.createFileReference(mockFileUploadOptions, testFile);
116
-
129
+
130
+ expect(result.ok).toBe(true);
131
+ if (result.ok) expect(result.data).toEqual(mockFileReference);
117
132
  expect(mockSetOrganisationContext).toHaveBeenCalledWith(
118
133
  mockSupabase,
119
134
  mockFileUploadOptions.organisation_id
120
135
  );
121
-
122
136
  expect(mockUploadFile).toHaveBeenCalledWith(
123
137
  mockSupabase,
124
138
  testFile,
@@ -128,7 +142,6 @@ describe('[service] FileReferenceServiceImpl', () => {
128
142
  isPublic: mockFileUploadOptions.is_public
129
143
  })
130
144
  );
131
-
132
145
  expect(mockSupabase.rpc).toHaveBeenCalledWith(
133
146
  'data_file_reference_create',
134
147
  expect.objectContaining({
@@ -147,83 +160,59 @@ describe('[service] FileReferenceServiceImpl', () => {
147
160
  })
148
161
  );
149
162
 
150
- expect(result && typeof result === 'object').toBe(true);
151
- expect((result as any).id).toBeTruthy();
163
+ expect(result.ok).toBe(true);
164
+ if (result.ok) expect(result.data.id).toBeTruthy();
152
165
  });
153
166
 
154
167
  it('validates required options before upload', async () => {
155
168
  const testFile = createTestFile();
156
-
157
- await expect(service.createFileReference({ ...mockFileUploadOptions, table_name: '' }, testFile))
158
- .rejects.toThrow('table_name is required');
159
-
160
- await expect(service.createFileReference({ ...mockFileUploadOptions, record_id: '' }, testFile))
161
- .rejects.toThrow('record_id is required');
162
-
163
- await expect(service.createFileReference({ ...mockFileUploadOptions, folder: '' }, testFile))
164
- .rejects.toThrow('folder is required');
165
-
166
- await expect(service.createFileReference({ ...mockFileUploadOptions, organisation_id: undefined, userId: undefined }, testFile))
167
- .rejects.toThrow('organisation_id is required');
169
+ let result = await service.createFileReference({ ...mockFileUploadOptions, table_name: '' }, testFile);
170
+ expect(result.ok).toBe(false);
171
+ if (!result.ok) expect(result.error.message).toContain('table_name is required');
172
+ result = await service.createFileReference({ ...mockFileUploadOptions, record_id: '' }, testFile);
173
+ expect(result.ok).toBe(false);
174
+ if (!result.ok) expect(result.error.message).toContain('record_id is required');
175
+ result = await service.createFileReference({ ...mockFileUploadOptions, folder: '' }, testFile);
176
+ expect(result.ok).toBe(false);
177
+ if (!result.ok) expect(result.error.message).toContain('folder is required');
178
+ result = await service.createFileReference({ ...mockFileUploadOptions, organisation_id: undefined, userId: undefined }, testFile);
179
+ expect(result.ok).toBe(false);
180
+ if (!result.ok) expect(result.error.message).toContain('organisation_id is required');
168
181
  });
169
182
 
170
183
  it('validates file before upload', async () => {
171
- await expect(service.createFileReference(mockFileUploadOptions, null as any))
172
- .rejects.toThrow();
184
+ const result = await service.createFileReference(mockFileUploadOptions, null as any);
185
+ expect(result.ok).toBe(false);
173
186
  });
174
187
 
175
188
  it('handles upload errors gracefully', async () => {
176
189
  const testFile = createTestFile();
177
-
178
- mockUploadFile.mockResolvedValue({
179
- success: false,
180
- error: 'Upload failed'
181
- });
182
-
183
- await expect(service.createFileReference(mockFileUploadOptions, testFile))
184
- .rejects.toThrow('Upload failed');
190
+ mockUploadFile.mockResolvedValue({ ok: false, error: { code: 'UPLOAD_FAILED', message: 'Upload failed' } });
191
+ const result = await service.createFileReference(mockFileUploadOptions, testFile);
192
+ expect(result.ok).toBe(false);
193
+ if (!result.ok) expect(result.error.message).toBe('Upload failed');
185
194
  });
186
195
 
187
196
  it('handles RPC errors gracefully and rolls back upload', async () => {
188
197
  const testFile = createTestFile();
189
-
190
- mockSupabase.rpc.mockResolvedValue({
191
- data: null,
192
- error: { message: 'Database error' }
193
- });
194
-
195
- await expect(service.createFileReference(mockFileUploadOptions, testFile))
196
- .rejects.toThrow('Database error');
197
-
198
- // Verify rollback was attempted
198
+ mockSupabase.rpc.mockResolvedValue({ data: null, error: { message: 'Database error' } });
199
+ const result = await service.createFileReference(mockFileUploadOptions, testFile);
200
+ expect(result.ok).toBe(false);
201
+ if (!result.ok) expect(result.error.message).toContain('Database error');
199
202
  expect(mockDeleteFile).toHaveBeenCalled();
200
203
  });
201
204
 
202
205
  it('handles RPC returning null (permission denied)', async () => {
203
206
  const testFile = createTestFile();
204
-
205
- // Mock successful upload
206
- mockUploadFile.mockResolvedValue({
207
- success: true,
208
- path: 'org-123/documents/test.pdf'
209
- });
210
-
211
- // Mock RPC returning null (permission denied)
212
- mockSupabase.rpc.mockResolvedValue({
213
- data: null,
214
- error: null
215
- });
216
-
217
- // Mock app name lookup
207
+ mockUploadFile.mockResolvedValue({ ok: true, data: { path: 'org-123/documents/test.pdf' } });
208
+ mockSupabase.rpc.mockResolvedValue({ data: null, error: null });
218
209
  mockSupabase.from().select().eq().eq().single.mockResolvedValue({
219
210
  data: { name: 'test-app' },
220
211
  error: null
221
212
  });
222
-
223
- await expect(service.createFileReference(mockFileUploadOptions, testFile))
224
- .rejects.toThrow('insufficient permissions');
225
-
226
- // Verify rollback was attempted
213
+ const result = await service.createFileReference(mockFileUploadOptions, testFile);
214
+ expect(result.ok).toBe(false);
215
+ if (!result.ok) expect(result.error.message).toContain('insufficient permissions');
227
216
  expect(mockDeleteFile).toHaveBeenCalled();
228
217
  });
229
218
 
@@ -232,21 +221,13 @@ describe('[service] FileReferenceServiceImpl', () => {
232
221
 
233
222
  mockIsSuperAdmin.mockResolvedValueOnce(true);
234
223
 
235
- mockUploadFile.mockResolvedValue({
236
- success: true,
237
- path: 'org-123/documents/test.pdf'
238
- });
239
-
240
- mockSupabase.rpc.mockResolvedValue({
241
- data: 'file-ref-123',
242
- error: null
243
- });
244
-
245
- mockSupabase.from().select().eq().eq().eq().single.mockResolvedValue({
246
- data: mockFileReference,
247
- error: null
224
+ mockUploadFile.mockResolvedValue({ ok: true, data: { path: 'org-123/documents/test.pdf' } });
225
+ mockSupabase.rpc.mockResolvedValue({ data: 'file-ref-123', error: null });
226
+ mockSupabase.from.mockReturnValue({
227
+ select: vi.fn().mockReturnThis(),
228
+ eq: vi.fn().mockReturnThis(),
229
+ single: vi.fn().mockResolvedValue({ data: mockFileReference, error: null })
248
230
  });
249
-
250
231
  await service.createFileReference(mockFileUploadOptions, testFile);
251
232
 
252
233
  // Super admin check should be called if userId is provided
@@ -295,11 +276,7 @@ describe('[service] FileReferenceServiceImpl', () => {
295
276
  error: null
296
277
  });
297
278
 
298
- mockUploadFile.mockResolvedValue({
299
- success: true,
300
- path: 'users/user-123/documents/test.pdf'
301
- });
302
-
279
+ mockUploadFile.mockResolvedValue({ ok: true, data: { path: 'users/user-123/documents/test.pdf' } });
303
280
  mockSupabase.rpc.mockResolvedValue({
304
281
  data: 'file-ref-123',
305
282
  error: null
@@ -339,8 +316,9 @@ describe('[service] FileReferenceServiceImpl', () => {
339
316
  error: { message: 'Not authenticated' }
340
317
  });
341
318
 
342
- await expect(service.createFileReference(userScopedOptions, testFile))
343
- .rejects.toThrow('User must be authenticated');
319
+ const result = await service.createFileReference(userScopedOptions, testFile);
320
+ expect(result.ok).toBe(false);
321
+ if (!result.ok) expect(result.error.message).toContain('User must be authenticated');
344
322
  });
345
323
 
346
324
  it('invalidates cache after successful upload', async () => {
@@ -379,10 +357,9 @@ describe('[service] FileReferenceServiceImpl', () => {
379
357
  error: { message: 'Not found' }
380
358
  });
381
359
 
382
- await expect(service.createFileReference(mockFileUploadOptions, testFile))
383
- .rejects.toThrow('Failed to fetch created file reference');
384
-
385
- // Verify rollback was attempted
360
+ const result = await service.createFileReference(mockFileUploadOptions, testFile);
361
+ expect(result.ok).toBe(false);
362
+ if (!result.ok) expect(result.error.message).toBeTruthy();
386
363
  expect(mockDeleteFile).toHaveBeenCalled();
387
364
  });
388
365
  });
@@ -399,8 +376,7 @@ describe('[service] FileReferenceServiceImpl', () => {
399
376
  'test-record-123',
400
377
  'test-org-123'
401
378
  );
402
-
403
- expect(result).toEqual(mockFileReference);
379
+ expect(expectOk(result)).toEqual(mockFileReference);
404
380
  });
405
381
 
406
382
  it('returns null when no file reference found (PGRST116)', async () => {
@@ -414,8 +390,8 @@ describe('[service] FileReferenceServiceImpl', () => {
414
390
  'test-record-123',
415
391
  'test-org-123'
416
392
  );
417
-
418
- expect(result).toBeNull();
393
+ expect(result.ok).toBe(true);
394
+ expect(result.ok && result.data).toBeNull();
419
395
  });
420
396
 
421
397
  it('handles null organisation_id for user-scoped files', async () => {
@@ -439,8 +415,8 @@ describe('[service] FileReferenceServiceImpl', () => {
439
415
  );
440
416
 
441
417
  expect(queryBuilder.is).toHaveBeenCalledWith('organisation_id', null);
442
- expect(result).toBeDefined();
443
- expect(result?.organisation_id).toBeNull();
418
+ const data = expectOk(result);
419
+ expect(data?.organisation_id).toBeNull();
444
420
  });
445
421
 
446
422
  it('handles undefined organisation_id for user-scoped files', async () => {
@@ -464,8 +440,8 @@ describe('[service] FileReferenceServiceImpl', () => {
464
440
  );
465
441
 
466
442
  expect(queryBuilder.is).toHaveBeenCalledWith('organisation_id', null);
467
- expect(result).toBeDefined();
468
- expect(result?.organisation_id).toBeNull();
443
+ const data = expectOk(result);
444
+ expect(data?.organisation_id).toBeNull();
469
445
  });
470
446
 
471
447
  it('gets file reference by ID', async () => {
@@ -475,27 +451,18 @@ describe('[service] FileReferenceServiceImpl', () => {
475
451
  });
476
452
 
477
453
  const result = await service.getFileReferenceById('file-ref-123', 'test-org-123');
478
-
479
454
  expect(mockSupabase.rpc).toHaveBeenCalledWith(
480
455
  'data_file_reference_get',
481
- {
482
- p_file_reference_id: 'file-ref-123',
483
- p_organisation_id: 'test-org-123'
484
- }
456
+ { p_file_reference_id: 'file-ref-123', p_organisation_id: 'test-org-123' }
485
457
  );
486
-
487
- expect(result).toEqual(mockFileReference);
458
+ expect(expectOk(result)).toEqual(mockFileReference);
488
459
  });
489
460
 
490
461
  it('returns null when file reference by ID not found', async () => {
491
- mockSupabase.rpc.mockResolvedValue({
492
- data: [],
493
- error: null
494
- });
495
-
462
+ mockSupabase.rpc.mockResolvedValue({ data: [], error: null });
496
463
  const result = await service.getFileReferenceById('file-ref-123', 'test-org-123');
497
-
498
- expect(result).toBeNull();
464
+ expect(result.ok).toBe(true);
465
+ expect(result.ok && result.data).toBeNull();
499
466
  });
500
467
 
501
468
  it('gets files by category', async () => {
@@ -533,9 +500,9 @@ describe('[service] FileReferenceServiceImpl', () => {
533
500
  })
534
501
  );
535
502
 
536
- // The method constructs FileReference from RPC response
537
- expect(result).toHaveLength(1);
538
- expect(result[0]).toEqual({
503
+ const data = expectOk(result);
504
+ expect(data).toHaveLength(1);
505
+ expect(data[0]).toEqual({
539
506
  id: 'file-ref-123',
540
507
  table_name: 'test_table',
541
508
  record_id: 'test-record-123',
@@ -568,29 +535,15 @@ describe('[service] FileReferenceServiceImpl', () => {
568
535
 
569
536
  expect(mockSupabase.rpc).toHaveBeenCalledWith(
570
537
  'data_file_reference_count_get',
571
- {
572
- p_table_name: 'test_table',
573
- p_record_id: 'test-record-123',
574
- p_organisation_id: 'test-org-123'
575
- }
538
+ { p_table_name: 'test_table', p_record_id: 'test-record-123', p_organisation_id: 'test-org-123' }
576
539
  );
577
-
578
- expect(result).toBe(5);
540
+ expect(expectOk(result)).toBe(5);
579
541
  });
580
542
 
581
543
  it('returns 0 when file count RPC returns null', async () => {
582
- mockSupabase.rpc.mockResolvedValue({
583
- data: null,
584
- error: null
585
- });
586
-
587
- const result = await service.getFileCount(
588
- 'test_table',
589
- 'test-record-123',
590
- 'test-org-123'
591
- );
592
-
593
- expect(result).toBe(0);
544
+ mockSupabase.rpc.mockResolvedValue({ data: null, error: null });
545
+ const result = await service.getFileCount('test_table', 'test-record-123', 'test-org-123');
546
+ expect(expectOk(result)).toBe(0);
594
547
  });
595
548
 
596
549
  it('handles null organisation_id in getFileCount', async () => {
@@ -629,8 +582,7 @@ describe('[service] FileReferenceServiceImpl', () => {
629
582
  'test-record-123',
630
583
  'test-org-123'
631
584
  );
632
-
633
- expect(result).toBe('https://example.com/public-url');
585
+ expect(expectOk(result)).toBe('https://example.com/public-url');
634
586
  expect(mockGetPublicUrl).toHaveBeenCalled();
635
587
  });
636
588
 
@@ -652,8 +604,7 @@ describe('[service] FileReferenceServiceImpl', () => {
652
604
  'test-record-123',
653
605
  'test-org-123'
654
606
  );
655
-
656
- expect(result).toBe('https://example.com/signed-url');
607
+ expect(expectOk(result)).toBe('https://example.com/signed-url');
657
608
  expect(mockGetSignedUrl).toHaveBeenCalled();
658
609
  });
659
610
 
@@ -668,8 +619,8 @@ describe('[service] FileReferenceServiceImpl', () => {
668
619
  'test-record-123',
669
620
  'test-org-123'
670
621
  );
671
-
672
- expect(result).toBeNull();
622
+ expect(result.ok).toBe(true);
623
+ expect(result.ok && result.data).toBeNull();
673
624
  });
674
625
 
675
626
  it('gets signed URL for private file', async () => {
@@ -684,8 +635,7 @@ describe('[service] FileReferenceServiceImpl', () => {
684
635
  'test-org-123',
685
636
  3600
686
637
  );
687
-
688
- expect(result).toBe('https://example.com/signed-url');
638
+ expect(expectOk(result)).toBe('https://example.com/signed-url');
689
639
  expect(mockGetSignedUrl).toHaveBeenCalledWith(
690
640
  mockSupabase,
691
641
  'org-123/documents/test.pdf',
@@ -734,7 +684,7 @@ describe('[service] FileReferenceServiceImpl', () => {
734
684
 
735
685
  const result = await service.updateFileReference('file-ref-123', updates);
736
686
 
737
- expect(result).toEqual(expect.objectContaining(updates));
687
+ expect(expectOk(result)).toEqual(expect.objectContaining(updates));
738
688
  });
739
689
 
740
690
  it('deletes file reference successfully', async () => {
@@ -771,7 +721,7 @@ describe('[service] FileReferenceServiceImpl', () => {
771
721
  mockFileReference.is_public
772
722
  );
773
723
 
774
- expect(result).toBe(true);
724
+ expect(expectOk(result)).toBe(true);
775
725
  });
776
726
 
777
727
  it('deletes file reference without deleting file from storage', async () => {
@@ -848,17 +798,17 @@ describe('[service] FileReferenceServiceImpl', () => {
848
798
  'test-org-123'
849
799
  );
850
800
 
851
- // Verify result has correct structure (constructed from RPC response)
852
- expect(result).toHaveLength(1);
853
- expect(result[0].id).toBe('file-ref-123');
854
- expect(result[0].table_name).toBe('test_table');
855
- expect(result[0].record_id).toBe('test-record-123');
856
- expect(result[0].organisation_id).toBe('test-org-123');
857
- expect(result[0].file_path).toBe(mockFileReference.file_path);
858
- expect(result[0].file_metadata.fileName).toBe('test-document.pdf');
859
- expect(result[0].file_metadata.fileType).toBe('application/pdf');
860
- expect(result[0].is_public).toBe(mockFileReference.is_public);
861
- expect(result[0].app_id).toBe(mockFileReference.app_id);
801
+ const data = expectOk(result);
802
+ expect(data).toHaveLength(1);
803
+ expect(data[0].id).toBe('file-ref-123');
804
+ expect(data[0].table_name).toBe('test_table');
805
+ expect(data[0].record_id).toBe('test-record-123');
806
+ expect(data[0].organisation_id).toBe('test-org-123');
807
+ expect(data[0].file_path).toBe(mockFileReference.file_path);
808
+ expect(data[0].file_metadata.fileName).toBe('test-document.pdf');
809
+ expect(data[0].file_metadata.fileType).toBe('application/pdf');
810
+ expect(data[0].is_public).toBe(mockFileReference.is_public);
811
+ expect(data[0].app_id).toBe(mockFileReference.app_id);
862
812
  });
863
813
 
864
814
  it('returns empty array when no file references found', async () => {
@@ -873,7 +823,7 @@ describe('[service] FileReferenceServiceImpl', () => {
873
823
  'test-org-123'
874
824
  );
875
825
 
876
- expect(result).toEqual([]);
826
+ expect(expectOk(result)).toEqual([]);
877
827
  });
878
828
 
879
829
  it('filters invalid RPC response items', async () => {
@@ -893,10 +843,9 @@ describe('[service] FileReferenceServiceImpl', () => {
893
843
  'test-record-123',
894
844
  'test-org-123'
895
845
  );
896
-
897
- // Should only include valid items
898
- expect(result.length).toBeGreaterThan(0);
899
- expect(result.every(r => r.id && r.file_path && r.file_metadata)).toBe(true);
846
+ const data = expectOk(result);
847
+ expect(data.length).toBeGreaterThan(0);
848
+ expect(data.every(r => r.id && r.file_path && r.file_metadata)).toBe(true);
900
849
  });
901
850
 
902
851
  it('handles null organisation_id in listFileReferences', async () => {
@@ -918,45 +867,39 @@ describe('[service] FileReferenceServiceImpl', () => {
918
867
 
919
868
  describe('Bulk Operations', () => {
920
869
  it('uploads multiple files successfully', async () => {
921
- const files = [
922
- createTestFile('file1.pdf'),
923
- createTestFile('file2.pdf')
924
- ];
925
-
926
- // Mock successful uploads
870
+ const files = [createTestFile('file1.pdf'), createTestFile('file2.pdf')];
927
871
  mockSupabase.rpc
928
872
  .mockResolvedValueOnce({ data: 'file-ref-1', error: null })
929
873
  .mockResolvedValueOnce({ data: 'file-ref-2', error: null });
930
-
874
+ mockSupabase.from.mockReturnValue({
875
+ select: vi.fn().mockReturnThis(),
876
+ eq: vi.fn().mockReturnThis(),
877
+ single: vi.fn()
878
+ .mockResolvedValueOnce({ data: { ...mockFileReference, id: 'file-ref-1' }, error: null })
879
+ .mockResolvedValueOnce({ data: { ...mockFileReference, id: 'file-ref-2' }, error: null })
880
+ });
931
881
  const result = await service.uploadMultipleFiles(mockFileUploadOptions, files);
932
-
933
- expect(result.success).toHaveLength(2);
934
- expect(result.failed).toHaveLength(0);
882
+ const data = expectOk(result);
883
+ expect(data.success).toHaveLength(2);
884
+ expect(data.failed).toHaveLength(0);
935
885
  });
936
886
 
937
887
  it('handles partial failures in bulk upload', async () => {
938
- const files = [
939
- createTestFile('file1.pdf'),
940
- createTestFile('file2.pdf')
941
- ];
942
-
943
- // Mock one success, one failure
888
+ const files = [createTestFile('file1.pdf'), createTestFile('file2.pdf')];
944
889
  mockUploadFile
945
- .mockResolvedValueOnce({ success: true, path: 'path1' })
946
- .mockResolvedValueOnce({ success: false, error: 'Upload failed' });
947
-
948
- mockSupabase.rpc
949
- .mockResolvedValueOnce({ data: 'file-ref-1', error: null })
950
- .mockResolvedValueOnce({ data: null, error: { message: 'Database error' } });
951
-
952
- const result = await service.uploadMultipleFiles(mockFileUploadOptions, files);
953
-
954
- expect(result.success).toHaveLength(1);
955
- expect(result.failed).toHaveLength(1);
956
- expect(result.failed[0]).toEqual({
957
- file: files[1],
958
- error: 'Failed to upload file: Upload failed'
890
+ .mockResolvedValueOnce({ ok: true, data: { path: 'path1' } })
891
+ .mockResolvedValueOnce({ ok: false, error: { code: 'UPLOAD_FAILED', message: 'Upload failed' } });
892
+ mockSupabase.rpc.mockResolvedValueOnce({ data: 'file-ref-1', error: null });
893
+ mockSupabase.from.mockReturnValue({
894
+ select: vi.fn().mockReturnThis(),
895
+ eq: vi.fn().mockReturnThis(),
896
+ single: vi.fn().mockResolvedValue({ data: { ...mockFileReference, id: 'file-ref-1' }, error: null })
959
897
  });
898
+ const result = await service.uploadMultipleFiles(mockFileUploadOptions, files);
899
+ const data = expectOk(result);
900
+ expect(data.success).toHaveLength(1);
901
+ expect(data.failed).toHaveLength(1);
902
+ expect(data.failed[0].error).toBe('Upload failed');
960
903
  });
961
904
  });
962
905
 
@@ -967,32 +910,25 @@ describe('[service] FileReferenceServiceImpl', () => {
967
910
  error: { message: 'Permission denied', code: 'ERR' }
968
911
  });
969
912
 
970
- await expect(service.getFileReference('test_table', 'test-record-123', 'test-org-123'))
971
- .rejects.toThrow('Permission denied');
913
+ const result = await service.getFileReference('test_table', 'test-record-123', 'test-org-123');
914
+ expect(result.ok).toBe(false);
915
+ if (!result.ok) expect(result.error.message).toContain('Permission denied');
972
916
  });
973
917
 
974
918
  it('handles network errors gracefully', async () => {
975
919
  (mockSupabase.from() as any).select().eq().eq().eq().single.mockRejectedValue(new Error('Network error'));
976
-
977
- await expect(service.getFileReference('test_table', 'test-record-123', 'test-org-123'))
978
- .rejects.toThrow('Network error');
920
+ const result = await service.getFileReference('test_table', 'test-record-123', 'test-org-123');
921
+ expect(result.ok).toBe(false);
922
+ if (!result.ok) expect(result.error.message).toContain('Network error');
979
923
  });
980
924
 
981
925
  it('handles rollback when RPC fails after upload', async () => {
982
926
  const testFile = createTestFile();
983
-
984
- mockUploadFile.mockResolvedValue({
985
- success: true,
986
- path: 'org-123/documents/test.pdf'
987
- });
988
-
989
- mockSupabase.rpc.mockResolvedValue({
990
- data: null,
991
- error: { message: 'Database error' }
992
- });
993
-
994
- await expect(service.createFileReference(mockFileUploadOptions, testFile))
995
- .rejects.toThrow('Database error');
927
+ mockUploadFile.mockResolvedValue({ ok: true, data: { path: 'org-123/documents/test.pdf' } });
928
+ mockSupabase.rpc.mockResolvedValue({ data: null, error: { message: 'Database error' } });
929
+ const result = await service.createFileReference(mockFileUploadOptions, testFile);
930
+ expect(result.ok).toBe(false);
931
+ if (!result.ok) expect(result.error.message).toContain('Database error');
996
932
 
997
933
  // Verify rollback was attempted
998
934
  expect(mockDeleteFile).toHaveBeenCalledWith(
@@ -1020,8 +956,8 @@ describe('[service] FileReferenceServiceImpl', () => {
1020
956
  'test-record-123',
1021
957
  'test-org-123'
1022
958
  );
1023
-
1024
- expect(result).toBeNull();
959
+ expect(result.ok).toBe(true);
960
+ expect(result.ok && result.data).toBeNull();
1025
961
  });
1026
962
 
1027
963
  it('handles getFilesByCategory with category mismatch', async () => {
@@ -1048,7 +984,7 @@ describe('[service] FileReferenceServiceImpl', () => {
1048
984
  );
1049
985
 
1050
986
  // Should filter out mismatched category
1051
- expect(result).toHaveLength(0);
987
+ expect(expectOk(result)).toHaveLength(0);
1052
988
  });
1053
989
 
1054
990
  it('handles getFilesByCategory with empty response', async () => {
@@ -1061,7 +997,7 @@ describe('[service] FileReferenceServiceImpl', () => {
1061
997
  'test-org-123'
1062
998
  );
1063
999
 
1064
- expect(result).toEqual([]);
1000
+ expect(expectOk(result)).toEqual([]);
1065
1001
  });
1066
1002
 
1067
1003
  it('handles getFilesByCategory RPC errors with helpful message', async () => {
@@ -1070,12 +1006,14 @@ describe('[service] FileReferenceServiceImpl', () => {
1070
1006
  error: { message: 'RPC function error', code: 'ERR' }
1071
1007
  });
1072
1008
 
1073
- await expect(service.getFilesByCategory(
1009
+ const result = await service.getFilesByCategory(
1074
1010
  'test_table',
1075
1011
  'test-record-123',
1076
1012
  FileCategory.GENERAL_DOCUMENTS,
1077
1013
  'test-org-123'
1078
- )).rejects.toThrow('RPC function required');
1014
+ );
1015
+ expect(result.ok).toBe(false);
1016
+ if (!result.ok) expect(result.error.message).toContain('RPC function');
1079
1017
  });
1080
1018
 
1081
1019
  it('handles null organisation_id in getFilesByCategory', async () => {
@@ -1104,8 +1042,9 @@ describe('[service] FileReferenceServiceImpl', () => {
1104
1042
  error: { message: 'Update failed', code: 'ERR' }
1105
1043
  });
1106
1044
 
1107
- await expect(service.updateFileReference('file-ref-123', updates))
1108
- .rejects.toThrow('Update failed');
1045
+ const result = await service.updateFileReference('file-ref-123', updates);
1046
+ expect(result.ok).toBe(false);
1047
+ if (!result.ok) expect(result.error.message).toContain('Update failed');
1109
1048
  });
1110
1049
 
1111
1050
  it('handles deleteFileReference when file reference not found', async () => {
@@ -1127,56 +1066,44 @@ describe('[service] FileReferenceServiceImpl', () => {
1127
1066
  false
1128
1067
  );
1129
1068
 
1130
- expect(result).toBe(true);
1069
+ expect(expectOk(result)).toBe(true);
1131
1070
  });
1132
1071
 
1133
1072
  it('handles uploadMultipleFiles with all files failing', async () => {
1134
- const files = [
1135
- createTestFile('file1.pdf'),
1136
- createTestFile('file2.pdf')
1137
- ];
1138
-
1139
- mockUploadFile.mockResolvedValue({
1140
- success: false,
1141
- error: 'Upload failed'
1142
- });
1143
-
1073
+ const files = [createTestFile('file1.pdf'), createTestFile('file2.pdf')];
1074
+ mockUploadFile.mockResolvedValue({ ok: false, error: { code: 'UPLOAD_FAILED', message: 'Upload failed' } });
1144
1075
  const result = await service.uploadMultipleFiles(mockFileUploadOptions, files);
1145
-
1146
- expect(result.success).toHaveLength(0);
1147
- expect(result.failed).toHaveLength(2);
1148
- expect(result.total).toBe(2);
1149
- expect(result.successful).toBe(0);
1150
- expect(result.failed.every(f => f.error.includes('Upload failed'))).toBe(true);
1076
+ const data = expectOk(result);
1077
+ expect(data.success).toHaveLength(0);
1078
+ expect(data.failed).toHaveLength(2);
1079
+ expect(data.total).toBe(2);
1080
+ expect(data.successful).toBe(0);
1081
+ expect(data.failed.every(f => f.error.includes('Upload failed'))).toBe(true);
1151
1082
  });
1152
1083
 
1153
1084
  it('handles uploadMultipleFiles with mixed success and failure', async () => {
1154
- const files = [
1155
- createTestFile('file1.pdf'),
1156
- createTestFile('file2.pdf'),
1157
- createTestFile('file3.pdf')
1158
- ];
1159
-
1085
+ const files = [createTestFile('file1.pdf'), createTestFile('file2.pdf'), createTestFile('file3.pdf')];
1160
1086
  mockUploadFile
1161
- .mockResolvedValueOnce({ success: true, path: 'path1' })
1162
- .mockResolvedValueOnce({ success: false, error: 'Network timeout' })
1163
- .mockResolvedValueOnce({ success: true, path: 'path3' });
1164
-
1087
+ .mockResolvedValueOnce({ ok: true, data: { path: 'path1' } })
1088
+ .mockResolvedValueOnce({ ok: false, error: { code: 'UPLOAD_FAILED', message: 'Network timeout' } })
1089
+ .mockResolvedValueOnce({ ok: true, data: { path: 'path3' } });
1165
1090
  mockSupabase.rpc
1166
1091
  .mockResolvedValueOnce({ data: 'file-ref-1', error: null })
1167
1092
  .mockResolvedValueOnce({ data: 'file-ref-3', error: null });
1168
-
1169
- mockSupabase.from().select().eq().eq().single
1170
- .mockResolvedValueOnce({ data: { ...mockFileReference, id: 'file-ref-1' }, error: null })
1171
- .mockResolvedValueOnce({ data: { ...mockFileReference, id: 'file-ref-3' }, error: null });
1172
-
1093
+ mockSupabase.from.mockReturnValue({
1094
+ select: vi.fn().mockReturnThis(),
1095
+ eq: vi.fn().mockReturnThis(),
1096
+ single: vi.fn()
1097
+ .mockResolvedValueOnce({ data: { ...mockFileReference, id: 'file-ref-1' }, error: null })
1098
+ .mockResolvedValueOnce({ data: { ...mockFileReference, id: 'file-ref-3' }, error: null })
1099
+ });
1173
1100
  const result = await service.uploadMultipleFiles(mockFileUploadOptions, files);
1174
-
1175
- expect(result.success).toHaveLength(2);
1176
- expect(result.failed).toHaveLength(1);
1177
- expect(result.total).toBe(3);
1178
- expect(result.successful).toBe(2);
1179
- expect(result.failed[0].error).toContain('Network timeout');
1101
+ const data = expectOk(result);
1102
+ expect(data.success).toHaveLength(2);
1103
+ expect(data.failed).toHaveLength(1);
1104
+ expect(data.total).toBe(3);
1105
+ expect(data.successful).toBe(2);
1106
+ expect(data.failed[0].error).toContain('Network timeout');
1180
1107
  });
1181
1108
 
1182
1109
  it('handles getSignedUrl with null file path', async () => {
@@ -1191,7 +1118,8 @@ describe('[service] FileReferenceServiceImpl', () => {
1191
1118
  'test-org-123'
1192
1119
  );
1193
1120
 
1194
- expect(result).toBeNull();
1121
+ expect(result.ok).toBe(true);
1122
+ expect(result.ok && result.data).toBeNull();
1195
1123
  });
1196
1124
 
1197
1125
  it('handles getSignedUrl with RPC error', async () => {
@@ -1200,28 +1128,28 @@ describe('[service] FileReferenceServiceImpl', () => {
1200
1128
  error: { message: 'File not found' }
1201
1129
  });
1202
1130
 
1203
- await expect(service.getSignedUrl(
1131
+ const result = await service.getSignedUrl(
1204
1132
  'test_table',
1205
1133
  'test-record-123',
1206
1134
  'test-org-123'
1207
- )).rejects.toThrow('File not found');
1135
+ );
1136
+ expect(result.ok).toBe(false);
1137
+ if (!result.ok) expect(result.error.message).toContain('File not found');
1208
1138
  });
1209
1139
 
1210
- it('handles getSignedUrl when getSignedUrl helper returns null', async () => {
1140
+ it('handles getSignedUrl when getSignedUrl helper returns err', async () => {
1211
1141
  mockSupabase.rpc.mockResolvedValue({
1212
1142
  data: 'org-123/documents/test.pdf',
1213
1143
  error: null
1214
1144
  });
1215
-
1216
- mockGetSignedUrl.mockResolvedValue(null);
1217
-
1145
+ mockGetSignedUrl.mockResolvedValue({ ok: false, error: { code: 'SIGNED_URL_FAILED', message: 'Failed' } });
1218
1146
  const result = await service.getSignedUrl(
1219
1147
  'test_table',
1220
1148
  'test-record-123',
1221
1149
  'test-org-123'
1222
1150
  );
1223
-
1224
- expect(result).toBeNull();
1151
+ expect(result.ok).toBe(false);
1152
+ if (!result.ok) expect(result.error.code).toBe('SIGNED_URL_FAILED');
1225
1153
  });
1226
1154
  });
1227
1155
  });
@@ -1250,10 +1178,10 @@ describe('[utility] uploadFileWithReference', () => {
1250
1178
  });
1251
1179
 
1252
1180
  const result = await uploadFileWithReference(mockSupabase, publicOptions, testFile);
1253
-
1254
- expect(result).toHaveProperty('file_reference');
1255
- expect(result.file_url).toBe('https://example.com/public-url');
1256
- expect(result.signed_url).toBeUndefined();
1181
+ const data = expectOk(result);
1182
+ expect(data).toHaveProperty('file_reference');
1183
+ expect(data.file_url).toBe('https://example.com/public-url');
1184
+ expect(data.signed_url).toBeUndefined();
1257
1185
  expect(mockGetPublicUrl).toHaveBeenCalled();
1258
1186
  });
1259
1187
 
@@ -1271,22 +1199,19 @@ describe('[utility] uploadFileWithReference', () => {
1271
1199
  });
1272
1200
 
1273
1201
  const result = await uploadFileWithReference(mockSupabase, mockFileUploadOptions, testFile);
1274
-
1275
- expect(result).toHaveProperty('file_reference');
1276
- expect(result.file_url).toBe('https://example.com/signed-url');
1277
- expect(result.signed_url).toBe('https://example.com/signed-url');
1202
+ const data = expectOk(result);
1203
+ expect(data).toHaveProperty('file_reference');
1204
+ expect(data.file_url).toBe('https://example.com/signed-url');
1205
+ expect(data.signed_url).toBe('https://example.com/signed-url');
1278
1206
  expect(mockGetSignedUrl).toHaveBeenCalled();
1279
1207
  });
1280
1208
 
1281
1209
  it('handles upload failures gracefully', async () => {
1282
- mockUploadFile.mockResolvedValue({
1283
- success: false,
1284
- error: 'Upload failed'
1285
- });
1286
-
1210
+ mockUploadFile.mockResolvedValue({ ok: false, error: { code: 'UPLOAD_FAILED', message: 'Upload failed' } });
1287
1211
  const testFile = createTestFile();
1288
- await expect(uploadFileWithReference(mockSupabase, mockFileUploadOptions, testFile))
1289
- .rejects.toThrow('Upload failed');
1212
+ const result = await uploadFileWithReference(mockSupabase, mockFileUploadOptions, testFile);
1213
+ expect(result.ok).toBe(false);
1214
+ if (!result.ok) expect(result.error.message).toBe('Upload failed');
1290
1215
  });
1291
1216
 
1292
1217
  it('handles URL generation failures gracefully', async () => {
@@ -1302,12 +1227,12 @@ describe('[utility] uploadFileWithReference', () => {
1302
1227
  error: null
1303
1228
  });
1304
1229
 
1305
- mockGetSignedUrl.mockResolvedValue(null);
1230
+ mockGetSignedUrl.mockResolvedValue({ ok: false, error: { code: 'SIGNED_URL_FAILED', message: 'Failed' } });
1306
1231
 
1307
1232
  const result = await uploadFileWithReference(mockSupabase, mockFileUploadOptions, testFile);
1308
-
1309
- expect(result).toHaveProperty('file_reference');
1310
- expect(result.file_url).toBe('');
1311
- expect(result.signed_url).toBeUndefined();
1233
+ const data = expectOk(result);
1234
+ expect(data).toHaveProperty('file_reference');
1235
+ expect(data.file_url).toBe('');
1236
+ expect(data.signed_url).toBeUndefined();
1312
1237
  });
1313
1238
  });