@jmruthers/pace-core 0.6.8 → 0.6.10

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 (669) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/audit-tool/audits/02-project-structure.cjs +97 -32
  3. package/audit-tool/audits/03-architecture.cjs +145 -19
  4. package/audit-tool/audits/04-code-quality.cjs +86 -1
  5. package/audit-tool/audits/06-security-rbac.cjs +109 -11
  6. package/cursor-rules/02-project-structure.mdc +2 -26
  7. package/cursor-rules/05-styling.mdc +84 -6
  8. package/cursor-rules/06-security-rbac.mdc +124 -1
  9. package/dist/{DataTable-6RMSCQJ6.js → DataTable-SAXFG4XI.js} +11 -13
  10. package/dist/{AuthService-DmfO5rGS.d.ts → InactivityServiceProvider-DHryoh6K.d.ts} +24 -249
  11. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +7 -0
  12. package/dist/{UnifiedAuthProvider-CKvHP1MK.d.ts → UnifiedAuthProvider-CiBAl9-s.d.ts} +34 -22
  13. package/dist/{api-7P7DI652.js → api-F47QJ7FX.js} +3 -3
  14. package/dist/assets/app-icons/admin_favicon.svg +462 -0
  15. package/dist/assets/app-icons/base_favicon.svg +85 -0
  16. package/dist/assets/app-icons/cake_favicon.svg +68 -0
  17. package/dist/assets/app-icons/core_favicon.svg +256 -0
  18. package/dist/assets/app-icons/gear_favicon.svg +91 -0
  19. package/dist/assets/app-icons/medi_favicon.svg +92 -0
  20. package/dist/assets/app-icons/mint_favicon.svg +83 -0
  21. package/dist/assets/app-icons/pace_favicon.svg +49 -0
  22. package/dist/assets/app-icons/pump_favicon.svg +68 -0
  23. package/dist/assets/app-icons/seed_favicon.svg +91 -0
  24. package/dist/assets/app-icons/team_favicon.svg +67 -0
  25. package/dist/assets/app-icons/trac_favicon.svg +112 -0
  26. package/dist/assets/app-icons/trip_favicon.svg +102 -0
  27. package/dist/audit-Z6ZZBWLU.js +3 -0
  28. package/dist/chunk-3GWSPISD.js +61 -0
  29. package/dist/{chunk-4DDCYDQ3.js → chunk-66R6RLUZ.js} +12 -27
  30. package/dist/{chunk-FYHN4DD5.js → chunk-7YDC7LMU.js} +80 -8
  31. package/dist/{chunk-S7DKJPLT.js → chunk-BCTXBU6U.js} +22 -17
  32. package/dist/{chunk-TTRFSOKR.js → chunk-BTHN5MKC.js} +4 -4
  33. package/dist/{chunk-A3W6LW53.js → chunk-DDMPHZ3D.js} +6 -18
  34. package/dist/{chunk-MPBLMWVR.js → chunk-FBZ7U3ID.js} +140 -92
  35. package/dist/chunk-FN52B75D.js +246 -0
  36. package/dist/{chunk-5W2A3DRC.js → chunk-JJEYZ3DX.js} +5 -4
  37. package/dist/chunk-KPYQWGFQ.js +183 -0
  38. package/dist/{chunk-IUBRCBSY.js → chunk-KSNLMI7N.js} +14 -8
  39. package/dist/chunk-KYURMOQM.js +977 -0
  40. package/dist/{chunk-LX6U42O3.js → chunk-LNHFAF4X.js} +160 -58
  41. package/dist/{chunk-NKHKXPI4.js → chunk-MPY44PWB.js} +683 -627
  42. package/dist/{chunk-AHU7G2R5.js → chunk-NIU6DPQV.js} +10 -6
  43. package/dist/{chunk-HF6O3O37.js → chunk-RMLY6KB5.js} +1 -1
  44. package/dist/{chunk-6GLLNA6U.js → chunk-SACF5YSM.js} +1 -1
  45. package/dist/{chunk-EURB7QFZ.js → chunk-TFIPNIPE.js} +867 -534
  46. package/dist/{chunk-OJ4SKRSV.js → chunk-UZNAFKGW.js} +25 -5
  47. package/dist/chunk-W46INAVW.js +1216 -0
  48. package/dist/chunk-X5EAU5G7.js +793 -0
  49. package/dist/{chunk-T5CVK4R3.js → chunk-Y4PF6HIM.js} +110 -64
  50. package/dist/components.d.ts +8 -86
  51. package/dist/components.js +21 -55
  52. package/dist/{database.generated-CcnC_DRc.d.ts → database.generated-DT8JTZiP.d.ts} +12 -12
  53. package/dist/eslint-rules/rules/05-styling.cjs +507 -0
  54. package/dist/eslint-rules/rules/06-security-rbac.cjs +10 -0
  55. package/dist/{event-CW5YB_2p.d.ts → event-WTAQuGcq.d.ts} +1 -1
  56. package/dist/{functions-lBy5L2ry.d.ts → functions-DH45k8ec.d.ts} +1 -1
  57. package/dist/hooks.d.ts +12 -11
  58. package/dist/hooks.js +69 -44
  59. package/dist/index.d.ts +380 -32
  60. package/dist/index.js +46 -32
  61. package/dist/papaparseLoader-WG2UXQ22.js +7 -0
  62. package/dist/providers.d.ts +28 -14
  63. package/dist/providers.js +5 -5
  64. package/dist/rbac/eslint-rules.js +2 -2
  65. package/dist/rbac/index.d.ts +58 -214
  66. package/dist/rbac/index.js +11 -11
  67. package/dist/theming/runtime.d.ts +9 -3
  68. package/dist/theming/runtime.js +2 -2
  69. package/dist/{timezone-BZe_eUxx.d.ts → timezone-K-ptz3HO.d.ts} +22 -23
  70. package/dist/{types-t9H8qKRw.d.ts → types-BE2sEHKd.d.ts} +1 -1
  71. package/dist/{types-BeoeWV5I.d.ts → types-CvOPXWWZ.d.ts} +6 -5
  72. package/dist/{types-DXstZpNI.d.ts → types-D05dCGma.d.ts} +56 -149
  73. package/dist/types-Dr8sNhER.d.ts +50 -0
  74. package/dist/types.d.ts +5 -5
  75. package/dist/{PublicPageProvider-CIGSujI2.d.ts → usePublicPageContext-vxBlEHO9.d.ts} +294 -151
  76. package/dist/{usePublicRouteParams-MamNgwqe.d.ts → usePublicRouteParams-G3Ks53mk.d.ts} +8 -7
  77. package/dist/utils.d.ts +301 -137
  78. package/dist/utils.js +42 -41
  79. package/dist/{validation-643vUDZW.d.ts → validation-g5n0hDkh.d.ts} +2 -2
  80. package/docs/api/modules.md +542 -549
  81. package/docs/api-reference/components.md +5 -5
  82. package/docs/api-reference/rpc-functions.md +3 -3
  83. package/docs/implementation-guides/data-tables.md +256 -8
  84. package/docs/rbac/RBAC_CONTRACT.md +0 -12
  85. package/docs/standards/2-project-structure-standards.md +12 -74
  86. package/docs/standards/6-security-rbac-standards.md +222 -7
  87. package/docs/standards/7-api-tech-stack-standards.md +91 -3
  88. package/docs/testing/README.md +10 -0
  89. package/docs/testing/test-setup-for-consumers.md +914 -0
  90. package/eslint-config-pace-core.cjs +4 -0
  91. package/package.json +1 -1
  92. package/scripts/eslint-audit.cjs +110 -11
  93. package/src/__mocks__/lucide-react.ts +0 -2
  94. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -2
  95. package/src/__tests__/index.test.ts +532 -0
  96. package/src/__tests__/integration/UserProfile.test.tsx +1 -1
  97. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +10 -8
  98. package/src/__tests__/rls-policies.test.ts +3 -2
  99. package/src/assets/app-icons/admin_favicon.svg +462 -0
  100. package/src/assets/app-icons/base_favicon.svg +85 -0
  101. package/src/assets/app-icons/cake_favicon.svg +68 -0
  102. package/src/assets/app-icons/core_favicon.svg +256 -0
  103. package/src/assets/app-icons/gear_favicon.svg +91 -0
  104. package/src/assets/app-icons/index.ts +83 -0
  105. package/src/assets/app-icons/medi_favicon.svg +92 -0
  106. package/src/assets/app-icons/mint_favicon.svg +83 -0
  107. package/src/assets/app-icons/pace_favicon.svg +49 -0
  108. package/src/assets/app-icons/pump_favicon.svg +68 -0
  109. package/src/assets/app-icons/seed_favicon.svg +91 -0
  110. package/src/assets/app-icons/team_favicon.svg +67 -0
  111. package/src/assets/app-icons/trac_favicon.svg +112 -0
  112. package/src/assets/app-icons/trip_favicon.svg +102 -0
  113. package/src/components/AddressField/AddressField.test.tsx +378 -3
  114. package/src/components/AddressField/AddressField.tsx +2 -2
  115. package/src/components/AddressField/types.ts +2 -2
  116. package/src/components/Alert/Alert.test.tsx +35 -25
  117. package/src/components/Alert/Alert.tsx +8 -8
  118. package/src/components/AppSwitcher/AppSwitcher.test.tsx +1250 -0
  119. package/src/components/AppSwitcher/AppSwitcher.tsx +315 -0
  120. package/src/components/Avatar/Avatar.test.tsx +11 -1
  121. package/src/components/Avatar/Avatar.tsx +3 -2
  122. package/src/components/Badge/Badge.test.tsx +11 -1
  123. package/src/components/Button/Button.test.tsx +13 -3
  124. package/src/components/Calendar/Calendar.test.tsx +523 -131
  125. package/src/components/Calendar/Calendar.tsx +107 -488
  126. package/src/components/Card/Card.test.tsx +220 -249
  127. package/src/components/Checkbox/Checkbox.test.tsx +58 -174
  128. package/src/components/ContextSelector/ContextSelector.tsx +3 -3
  129. package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +360 -0
  130. package/src/components/DataTable/DataTable.tsx +2 -2
  131. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +1 -1
  132. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +2 -2
  133. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +1 -1
  134. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +485 -0
  135. package/src/components/DataTable/__tests__/DataTable.test.tsx +2 -2
  136. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +1 -1
  137. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +76 -580
  138. package/src/components/DataTable/__tests__/README.md +1 -1
  139. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +1 -1
  140. package/src/components/DataTable/__tests__/keyboard.test.tsx +1 -1
  141. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +1 -3
  142. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -6
  143. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +14 -6
  144. package/src/components/DataTable/components/ActionButtons.tsx +9 -4
  145. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +3 -3
  146. package/src/components/DataTable/components/ColumnFilter.tsx +2 -7
  147. package/src/components/DataTable/components/DataTableCore.tsx +44 -52
  148. package/src/components/DataTable/components/DataTableLayout.tsx +37 -26
  149. package/src/components/DataTable/components/DataTableModals.tsx +118 -30
  150. package/src/components/DataTable/components/DataTableToolbar.tsx +2 -2
  151. package/src/components/DataTable/components/EditFields.tsx +6 -47
  152. package/src/components/DataTable/components/EditableRow.tsx +8 -8
  153. package/src/components/DataTable/components/EmptyState.tsx +6 -3
  154. package/src/components/DataTable/components/FilterRow.tsx +18 -11
  155. package/src/components/DataTable/components/GroupingDropdown.tsx +0 -1
  156. package/src/components/DataTable/components/ImportModal.tsx +305 -133
  157. package/src/components/DataTable/components/LoadingState.tsx +2 -2
  158. package/src/components/DataTable/components/PaginationControls.tsx +0 -4
  159. package/src/components/DataTable/components/RowComponent.tsx +42 -22
  160. package/src/components/DataTable/components/UnifiedTableBody.tsx +52 -12
  161. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +51 -463
  162. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +122 -116
  163. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +40 -68
  164. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +9 -137
  165. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +57 -17
  166. package/src/components/DataTable/components/__tests__/DataTableCore.test.tsx +792 -0
  167. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +24 -65
  168. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +467 -0
  169. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +8 -125
  170. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +528 -56
  171. package/src/components/DataTable/components/__tests__/EditFields.test.tsx +526 -0
  172. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +1 -68
  173. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +8 -25
  174. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +3 -62
  175. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +9 -14
  176. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +50 -186
  177. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +39 -97
  178. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +13 -103
  179. package/src/components/DataTable/components/__tests__/RowComponent.test.tsx +629 -0
  180. package/src/components/DataTable/components/__tests__/SortIndicator.test.tsx +135 -0
  181. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +31 -171
  182. package/src/components/DataTable/components/__tests__/cellValueUtils.test.ts +453 -0
  183. package/src/components/DataTable/components/hooks/useImportModalFocus.test.ts +184 -0
  184. package/src/components/DataTable/components/hooks/usePermissionTracking.test.ts +381 -0
  185. package/src/components/DataTable/context/DataTableContext.tsx +9 -10
  186. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +12 -26
  187. package/src/components/DataTable/core/ColumnFactory.ts +3 -3
  188. package/src/components/DataTable/core/ColumnManager.ts +0 -1
  189. package/src/components/DataTable/core/DataManager.ts +4 -2
  190. package/src/components/DataTable/core/LocalDataAdapter.ts +1 -1
  191. package/src/components/DataTable/core/PluginRegistry.ts +2 -2
  192. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +114 -2
  193. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +103 -5
  194. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +57 -0
  195. package/src/components/DataTable/core/__tests__/DataManager.test.ts +63 -0
  196. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +42 -9
  197. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +29 -7
  198. package/src/components/DataTable/core/__tests__/StateManager.test.ts +58 -4
  199. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +16 -21
  200. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +93 -4
  201. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +227 -54
  202. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +215 -62
  203. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +217 -39
  204. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +101 -6
  205. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +157 -27
  206. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +80 -0
  207. package/src/components/DataTable/hooks/__tests__/useKeyboardNavigation.test.ts +787 -0
  208. package/src/components/DataTable/hooks/__tests__/useServerSideDataEffect.test.ts +258 -0
  209. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +298 -23
  210. package/src/components/DataTable/hooks/__tests__/useTableHandlers.test.ts +440 -0
  211. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +12 -9
  212. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +12 -9
  213. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +1 -1
  214. package/src/components/DataTable/hooks/useDataTablePermissions.ts +11 -22
  215. package/src/components/DataTable/hooks/useDataTableState.ts +20 -24
  216. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +5 -5
  217. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +13 -1
  218. package/src/components/DataTable/hooks/useTableColumns.ts +36 -38
  219. package/src/components/DataTable/hooks/useTableHandlers.ts +8 -20
  220. package/src/components/DataTable/index.ts +24 -2
  221. package/src/components/DataTable/types.ts +6 -3
  222. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +3 -67
  223. package/src/components/DataTable/utils/__tests__/aggregationUtils.test.ts +288 -0
  224. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +3 -60
  225. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +1 -1
  226. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +9 -21
  227. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +102 -86
  228. package/src/components/DataTable/utils/__tests__/paginationUtils.test.ts +593 -0
  229. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +33 -49
  230. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +208 -0
  231. package/src/components/DataTable/utils/a11yUtils.ts +1 -1
  232. package/src/components/DataTable/utils/aggregationUtils.ts +5 -5
  233. package/src/components/DataTable/utils/errorHandling.ts +3 -1
  234. package/src/components/DataTable/utils/exportUtils.ts +1 -1
  235. package/src/components/DataTable/utils/flexibleImport.ts +2 -2
  236. package/src/components/DataTable/utils/hierarchicalSorting.ts +3 -3
  237. package/src/components/DataTable/utils/paginationUtils.ts +1 -1
  238. package/src/components/DataTable/utils/performanceUtils.ts +1 -1
  239. package/src/components/DataTable/utils/selectFieldUtils.ts +127 -0
  240. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +17 -24
  241. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +1 -1
  242. package/src/components/DateTimeField/DateTimeField.test.tsx +2 -15
  243. package/src/components/DateTimeField/DateTimeField.tsx +1 -1
  244. package/src/components/Dialog/Dialog.test.tsx +2007 -407
  245. package/src/components/Dialog/Dialog.tsx +97 -192
  246. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +2 -62
  247. package/src/components/ErrorBoundary/ErrorBoundaryContext.context.ts +17 -0
  248. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +2 -45
  249. package/src/components/ErrorBoundary/ErrorBoundaryContext.types.ts +41 -0
  250. package/src/components/ErrorBoundary/index.ts +3 -4
  251. package/src/components/ErrorBoundary/useErrorBoundaryContext.ts +20 -0
  252. package/src/components/FileDisplay/FileDisplay.test.tsx +454 -222
  253. package/src/components/FileDisplay/FileDisplay.tsx +14 -12
  254. package/src/components/FileDisplay/index.tsx +1 -1
  255. package/src/components/FileUpload/FileUpload.test.tsx +54 -18
  256. package/src/components/FileUpload/FileUpload.tsx +10 -7
  257. package/src/components/FileUpload/index.tsx +1 -1
  258. package/src/components/Footer/Footer.test.tsx +33 -114
  259. package/src/components/Form/Form.test.tsx +388 -68
  260. package/src/components/Form/Form.tsx +57 -42
  261. package/src/components/Header/Header.test.tsx +645 -154
  262. package/src/components/Header/Header.tsx +52 -43
  263. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +35 -76
  264. package/src/components/Input/Input.test.tsx +34 -120
  265. package/src/components/Label/Label.test.tsx +47 -46
  266. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +9 -12
  267. package/src/components/LoginForm/LoginForm.test.tsx +0 -1
  268. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1399 -82
  269. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  270. package/src/components/NavigationMenu/__tests__/useNavigationFiltering.test.ts +1934 -0
  271. package/src/components/NavigationMenu/useNavigationFiltering.ts +5 -15
  272. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +1307 -0
  273. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +47 -46
  274. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +81 -38
  275. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +87 -66
  276. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +245 -39
  277. package/src/components/PaceAppLayout/PaceAppLayout.tsx +14 -20
  278. package/src/components/PaceAppLayout/README.md +0 -9
  279. package/src/components/PaceAppLayout/test-setup.tsx +15 -9
  280. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +759 -3
  281. package/src/components/PaceLoginPage/PaceLoginPage.tsx +2 -3
  282. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +1 -1
  283. package/src/components/Progress/Progress.test.tsx +127 -1
  284. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +1196 -4
  285. package/src/components/ProtectedRoute/ProtectedRoute.tsx +24 -6
  286. package/src/components/PublicLayout/PublicLayout.test.tsx +1435 -14
  287. package/src/components/PublicLayout/PublicPageContext.ts +28 -0
  288. package/src/components/PublicLayout/PublicPageLayout.tsx +6 -6
  289. package/src/components/PublicLayout/PublicPageProvider.tsx +2 -41
  290. package/src/components/PublicLayout/usePublicPageContext.ts +36 -0
  291. package/src/components/Select/Select.test.tsx +46 -9
  292. package/src/components/Select/Select.tsx +31 -24
  293. package/src/components/Select/__tests__/context.test.tsx +56 -0
  294. package/src/components/Select/hooks/__tests__/useSelectEvents.test.ts +279 -0
  295. package/src/components/Select/hooks/__tests__/useSelectSearch.test.tsx +295 -0
  296. package/src/components/Select/hooks/__tests__/useSelectState.test.ts +254 -0
  297. package/src/components/Select/hooks/useSelectState.ts +16 -16
  298. package/src/components/Select/types.ts +3 -0
  299. package/src/components/Select/utils/__tests__/text.test.tsx +104 -0
  300. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +28 -112
  301. package/src/components/Switch/Switch.test.tsx +57 -153
  302. package/src/components/Table/Table.test.tsx +47 -317
  303. package/src/components/Tabs/Tabs.tsx +3 -3
  304. package/src/components/Textarea/Textarea.test.tsx +11 -38
  305. package/src/components/Toast/Toast.test.tsx +78 -569
  306. package/src/components/Tooltip/Tooltip.test.tsx +4 -21
  307. package/src/components/UserMenu/UserMenu.test.tsx +1 -21
  308. package/src/components/UserMenu/UserMenu.tsx +3 -6
  309. package/src/components/__tests__/index.test.ts +346 -0
  310. package/src/components/index.ts +12 -1
  311. package/src/constants/__tests__/performance.test.ts +91 -0
  312. package/src/hooks/__tests__/ServiceHooks.test.tsx +239 -129
  313. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -3
  314. package/src/hooks/__tests__/useApiFetch.unit.test.ts +1 -1
  315. package/src/hooks/__tests__/useAppConfig.unit.test.ts +88 -29
  316. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +282 -98
  317. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +53 -109
  318. package/src/hooks/__tests__/useDataTableState.test.ts +143 -49
  319. package/src/hooks/__tests__/useDebounce.unit.test.ts +94 -19
  320. package/src/hooks/__tests__/useEvents.unit.test.ts +100 -125
  321. package/src/hooks/__tests__/useFileDisplay.test.ts +540 -0
  322. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +1 -4
  323. package/src/hooks/__tests__/useFileUrl.unit.test.ts +27 -247
  324. package/src/hooks/__tests__/useFileUrlCache.test.ts +246 -56
  325. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +442 -68
  326. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +345 -560
  327. package/src/hooks/__tests__/useFormDialog.test.ts +51 -222
  328. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +1 -1
  329. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +1 -4
  330. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -1
  331. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +1 -1
  332. package/src/hooks/__tests__/usePermissionCache.test.ts +506 -0
  333. package/src/hooks/__tests__/usePreventTabReload.test.ts +255 -36
  334. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +17 -8
  335. package/src/hooks/__tests__/usePublicEvent.test.ts +16 -24
  336. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +12 -4
  337. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +3 -6
  338. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +1 -2
  339. package/src/hooks/__tests__/useQueryCache.test.ts +313 -66
  340. package/src/hooks/__tests__/useSessionDraft.test.ts +496 -103
  341. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +2 -2
  342. package/src/hooks/__tests__/useStorage.unit.test.ts +72 -102
  343. package/src/hooks/__tests__/useToast.test.ts +413 -0
  344. package/src/hooks/__tests__/useToast.unit.test.tsx +1 -1
  345. package/src/hooks/__tests__/useZodForm.unit.test.tsx +175 -21
  346. package/src/hooks/index.ts +13 -1
  347. package/src/hooks/public/usePublicEvent.test.ts +304 -0
  348. package/src/hooks/public/usePublicEvent.ts +11 -11
  349. package/src/hooks/public/usePublicEventLogo.test.ts +655 -120
  350. package/src/hooks/public/usePublicEventLogo.ts +2 -2
  351. package/src/hooks/public/usePublicFileDisplay.test.ts +723 -0
  352. package/src/hooks/public/usePublicFileDisplay.ts +79 -49
  353. package/src/hooks/public/usePublicRouteParams.test.ts +595 -0
  354. package/src/hooks/public/usePublicRouteParams.ts +2 -2
  355. package/src/hooks/services/useAuthService.ts +1 -1
  356. package/src/hooks/services/useEventService.ts +1 -1
  357. package/src/hooks/useAccessibleApps.test.ts +400 -0
  358. package/src/hooks/useAccessibleApps.ts +264 -0
  359. package/src/hooks/useAddressAutocomplete.test.ts +165 -42
  360. package/src/hooks/useAddressAutocomplete.ts +41 -28
  361. package/src/hooks/useAppConfig.ts +13 -3
  362. package/src/hooks/useDataTablePerformance.ts +13 -12
  363. package/src/hooks/useDataTableState.ts +5 -5
  364. package/src/hooks/useEventTheme.test.ts +66 -17
  365. package/src/hooks/useEventTheme.ts +1 -1
  366. package/src/hooks/useEvents.ts +8 -1
  367. package/src/hooks/useFileDisplay.ts +66 -33
  368. package/src/hooks/useFileReference.test.ts +365 -87
  369. package/src/hooks/useFileReference.ts +2 -6
  370. package/src/hooks/useFileUrlCache.ts +4 -1
  371. package/src/hooks/useFormDialog.ts +2 -2
  372. package/src/hooks/useInactivityTracker.ts +3 -3
  373. package/src/hooks/useOrganisationPermissions.test.ts +1 -2
  374. package/src/hooks/useOrganisationPermissions.ts +1 -4
  375. package/src/hooks/useOrganisationSecurity.test.ts +1 -30
  376. package/src/hooks/useOrganisationSecurity.ts +3 -3
  377. package/src/hooks/useOrganisations.ts +1 -1
  378. package/src/hooks/usePerformanceMonitor.ts +1 -1
  379. package/src/hooks/usePermissionCache.ts +2 -6
  380. package/src/hooks/useQueryCache.ts +7 -7
  381. package/src/hooks/useSessionDraft.ts +14 -11
  382. package/src/hooks/useSessionRestoration.ts +1 -1
  383. package/src/hooks/useStorage.ts +75 -40
  384. package/src/hooks/useToast.ts +2 -2
  385. package/src/hooks/useZodForm.ts +3 -3
  386. package/src/icons/__tests__/index.test.ts +133 -0
  387. package/src/icons/index.ts +1 -1
  388. package/src/index.ts +43 -4
  389. package/src/providers/OrganisationProvider.test.tsx +40 -0
  390. package/src/providers/OrganisationProvider.tsx +5 -5
  391. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +7 -12
  392. package/src/providers/__tests__/AuthProvider.test.tsx +22 -91
  393. package/src/providers/__tests__/EventProvider.test.tsx +16 -80
  394. package/src/providers/__tests__/InactivityProvider.test.tsx +29 -173
  395. package/src/providers/__tests__/OrganisationProvider.test.tsx +4 -5
  396. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +591 -0
  397. package/src/providers/__tests__/ProviderLifecycle.test.tsx +80 -196
  398. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +40 -133
  399. package/src/providers/__tests__/index.test.ts +138 -0
  400. package/src/providers/services/AuthServiceContext.ts +27 -0
  401. package/src/providers/services/AuthServiceProvider.tsx +81 -20
  402. package/src/providers/services/EventServiceContext.ts +25 -0
  403. package/src/providers/services/EventServiceProvider.tsx +11 -20
  404. package/src/providers/services/InactivityServiceContext.ts +25 -0
  405. package/src/providers/services/InactivityServiceProvider.tsx +7 -17
  406. package/src/providers/services/OrganisationServiceContext.ts +25 -0
  407. package/src/providers/services/OrganisationServiceProvider.tsx +7 -17
  408. package/src/providers/services/UnifiedAuthContext.ts +99 -0
  409. package/src/providers/services/UnifiedAuthProvider.test.tsx +212 -0
  410. package/src/providers/services/UnifiedAuthProvider.tsx +38 -143
  411. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +61 -95
  412. package/src/providers/services/__tests__/AuthServiceProvider.test.tsx +638 -0
  413. package/src/providers/services/__tests__/EventServiceProvider.test.tsx +839 -0
  414. package/src/providers/services/__tests__/InactivityServiceProvider.test.tsx +662 -0
  415. package/src/providers/services/__tests__/OrganisationServiceProvider.test.tsx +440 -0
  416. package/src/providers/services/__tests__/UnifiedAuthProvider.advanced.test.tsx +435 -0
  417. package/src/providers/services/__tests__/UnifiedAuthProvider.appId.test.tsx +408 -0
  418. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +55 -48
  419. package/src/providers/services/__tests__/contexts.test.tsx +281 -0
  420. package/src/providers/services/__tests__/useUnifiedAuth.test.tsx +251 -0
  421. package/src/providers/services/useUnifiedAuth.ts +29 -0
  422. package/src/rbac/README.md +5 -5
  423. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +9 -14
  424. package/src/rbac/__tests__/audit-batched.test.ts +550 -0
  425. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +1 -14
  426. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +43 -12
  427. package/src/rbac/__tests__/cache-invalidation.test.ts +8 -14
  428. package/src/rbac/__tests__/engine.comprehensive.test.ts +2 -7
  429. package/src/rbac/__tests__/index.test.ts +107 -0
  430. package/src/rbac/__tests__/performance.test.ts +451 -0
  431. package/src/rbac/__tests__/rbac-core.test.tsx +2 -2
  432. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -5
  433. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +1 -7
  434. package/src/rbac/__tests__/rbac-functions.test.ts +0 -1
  435. package/src/rbac/__tests__/rbac-integration.test.ts +0 -1
  436. package/src/rbac/__tests__/scenarios.user-role.test.tsx +21 -32
  437. package/src/rbac/adapters.test.tsx +654 -0
  438. package/src/rbac/adapters.tsx +24 -9
  439. package/src/rbac/api.test.ts +13 -217
  440. package/src/rbac/api.ts +85 -16
  441. package/src/rbac/audit-batched.ts +5 -4
  442. package/src/rbac/audit.test.ts +225 -28
  443. package/src/rbac/audit.ts +22 -17
  444. package/src/rbac/cache-invalidation.ts +18 -15
  445. package/src/rbac/cache.test.ts +123 -63
  446. package/src/rbac/cache.ts +3 -4
  447. package/src/rbac/components/AccessDenied.tsx +20 -18
  448. package/src/rbac/components/NavigationGuard.tsx +10 -8
  449. package/src/rbac/components/PagePermissionGuard.tsx +27 -25
  450. package/src/rbac/components/__tests__/AccessDenied.test.tsx +324 -0
  451. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +242 -71
  452. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +20 -37
  453. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +18 -17
  454. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +452 -129
  455. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -13
  456. package/src/rbac/config.test.ts +131 -48
  457. package/src/rbac/config.ts +11 -8
  458. package/src/rbac/docs/event-based-apps.md +26 -13
  459. package/src/rbac/engine.test.ts +496 -146
  460. package/src/rbac/engine.ts +53 -13
  461. package/src/rbac/errors.test.ts +99 -87
  462. package/src/rbac/eslint-rules.js +2 -2
  463. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -5
  464. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +601 -1
  465. package/src/rbac/hooks/permissions/__tests__/useAccessLevel.test.ts +622 -0
  466. package/src/rbac/hooks/permissions/__tests__/useCan.test.ts +798 -0
  467. package/src/rbac/hooks/permissions/__tests__/useMultiplePermissions.test.ts +843 -0
  468. package/src/rbac/hooks/permissions/__tests__/usePermissions.test.ts +545 -0
  469. package/src/rbac/hooks/permissions/useAccessLevel.ts +7 -8
  470. package/src/rbac/hooks/permissions/useCan.ts +12 -10
  471. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +57 -8
  472. package/src/rbac/hooks/permissions/usePermissions.ts +15 -14
  473. package/src/rbac/hooks/useCan.test.ts +319 -3
  474. package/src/rbac/hooks/usePermissions.test.ts +426 -0
  475. package/src/rbac/hooks/usePermissions.ts +5 -7
  476. package/src/rbac/hooks/useRBAC.test.ts +1669 -2
  477. package/src/rbac/hooks/useRBAC.ts +7 -11
  478. package/src/rbac/hooks/useResolvedScope.test.ts +442 -5
  479. package/src/rbac/hooks/useResolvedScope.ts +4 -1
  480. package/src/rbac/hooks/useResourcePermissions.test.ts +538 -1
  481. package/src/rbac/hooks/useResourcePermissions.ts +9 -7
  482. package/src/rbac/hooks/useRoleManagement.test.ts +659 -1
  483. package/src/rbac/hooks/useRoleManagement.ts +16 -12
  484. package/src/rbac/hooks/useSecureSupabase.ts +11 -12
  485. package/src/rbac/index.ts +32 -32
  486. package/src/rbac/permissions.test.ts +149 -68
  487. package/src/rbac/permissions.ts +0 -3
  488. package/src/rbac/request-deduplication.test.ts +347 -0
  489. package/src/rbac/secureClient.test.ts +112 -159
  490. package/src/rbac/secureClient.ts +46 -26
  491. package/src/rbac/security.test.ts +125 -44
  492. package/src/rbac/security.ts +7 -6
  493. package/src/rbac/types.test.ts +236 -0
  494. package/src/rbac/types.ts +7 -5
  495. package/src/rbac/utils/__tests__/clientSecurity.test.ts +192 -0
  496. package/src/rbac/utils/__tests__/contextValidator.test.ts +1 -3
  497. package/src/rbac/utils/__tests__/deep-equal.test.ts +23 -0
  498. package/src/rbac/utils/__tests__/eventContext.test.ts +10 -57
  499. package/src/rbac/utils/clientSecurity.ts +6 -4
  500. package/src/rbac/utils/contextValidator.ts +1 -2
  501. package/src/rbac/utils/eventContext.ts +2 -2
  502. package/src/services/AuthService.ts +13 -11
  503. package/src/services/EventService.ts +4 -5
  504. package/src/services/OrganisationService.ts +13 -30
  505. package/src/services/__tests__/AuthService.edge-cases.test.ts +746 -0
  506. package/src/services/__tests__/AuthService.restoreSession.test.ts +23 -3
  507. package/src/services/__tests__/AuthService.test.ts +4 -8
  508. package/src/services/__tests__/BaseService.edge-cases.test.ts +506 -0
  509. package/src/services/__tests__/BaseService.test.ts +49 -0
  510. package/src/services/__tests__/EventService.edge-cases.test.ts +633 -0
  511. package/src/services/__tests__/EventService.eventColours.test.ts +0 -12
  512. package/src/services/__tests__/EventService.test.ts +0 -7
  513. package/src/services/__tests__/InactivityService.edge-cases.test.ts +492 -0
  514. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -5
  515. package/src/services/__tests__/OrganisationService.edge-cases.test.ts +633 -0
  516. package/src/services/base/BaseService.test.ts +214 -0
  517. package/src/services/interfaces/IOrganisationService.ts +0 -1
  518. package/src/services/interfaces/__tests__/IAuthService.test.ts +190 -0
  519. package/src/services/interfaces/__tests__/IEventService.test.ts +176 -0
  520. package/src/services/interfaces/__tests__/IInactivityService.test.ts +183 -0
  521. package/src/services/interfaces/__tests__/IOrganisationService.test.ts +207 -0
  522. package/src/styles/core.css +1 -0
  523. package/src/theming/__tests__/runtime.test.ts +29 -94
  524. package/src/theming/parseEventColours.ts +18 -9
  525. package/src/theming/runtime.ts +1 -5
  526. package/src/types/__tests__/core.test.ts +397 -0
  527. package/src/types/__tests__/database-generated.test.ts +78 -0
  528. package/src/types/__tests__/file-reference.test.ts +270 -366
  529. package/src/types/__tests__/guards.test.ts +26 -26
  530. package/src/types/__tests__/index.test.ts +265 -0
  531. package/src/types/__tests__/type-validation.test.ts +3 -3
  532. package/src/types/__tests__/validation.test.ts +0 -2
  533. package/src/types/auth.ts +0 -1
  534. package/src/types/database.generated.ts +9 -9
  535. package/src/types/event.ts +1 -1
  536. package/src/types/rpc-responses.ts +33 -0
  537. package/src/types/supabase.ts +1 -2
  538. package/src/types/vitest-globals.d.ts +1 -1
  539. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +64 -77
  540. package/src/utils/__tests__/dynamicUtils.unit.test.ts +13 -0
  541. package/src/utils/__tests__/formatDate.unit.test.ts +1 -1
  542. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -1
  543. package/src/utils/__tests__/logger.unit.test.ts +1 -1
  544. package/src/utils/__tests__/performanceBenchmark.test.ts +1 -2
  545. package/src/utils/__tests__/performanceBudgets.unit.test.ts +48 -13
  546. package/src/utils/__tests__/request-deduplication.test.ts +349 -0
  547. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -1
  548. package/src/utils/__tests__/timezone.test.ts +1 -1
  549. package/src/utils/__tests__/validation.unit.test.ts +1 -2
  550. package/src/utils/__tests__/validationUtils.unit.test.ts +1 -1
  551. package/src/utils/app/appConfig.test.ts +235 -0
  552. package/src/utils/app/appIdResolver.test.ts +188 -20
  553. package/src/utils/app/appNameResolver.test.ts +18 -10
  554. package/src/utils/app/appNameResolver.ts +11 -9
  555. package/src/utils/app/appPortMap.test.ts +125 -0
  556. package/src/utils/app/appPortMap.ts +51 -0
  557. package/src/utils/app/buildAppUrl.test.ts +273 -0
  558. package/src/utils/app/buildAppUrl.ts +114 -0
  559. package/src/utils/audit/audit.test.ts +354 -39
  560. package/src/utils/context/organisationContext.test.ts +10 -4
  561. package/src/utils/context/organisationContext.ts +5 -5
  562. package/src/utils/context/sessionTracking.test.ts +354 -0
  563. package/src/utils/core/__tests__/cn.test.ts +66 -0
  564. package/src/utils/core/__tests__/debugLogger.test.ts +113 -0
  565. package/src/utils/core/__tests__/logger.test.ts +217 -0
  566. package/src/utils/core/debugLogger.ts +15 -8
  567. package/src/utils/core/logger.ts +20 -16
  568. package/src/utils/device/deviceFingerprint.test.ts +8 -5
  569. package/src/utils/device/deviceFingerprint.ts +3 -3
  570. package/src/utils/dynamic/__tests__/dynamicUtils.test.ts +185 -0
  571. package/src/utils/dynamic/__tests__/lazyLoad.test.tsx +156 -0
  572. package/src/utils/dynamic/createLazyComponent.tsx +38 -0
  573. package/src/utils/dynamic/dynamicUtils.ts +6 -6
  574. package/src/utils/dynamic/lazyLoad.tsx +8 -36
  575. package/src/utils/dynamic/papaparseLoader.ts +7 -0
  576. package/src/utils/file-reference/__tests__/file-reference.test.ts +583 -145
  577. package/src/utils/file-reference/index.ts +0 -1
  578. package/src/utils/formatting/formatDate.test.ts +22 -148
  579. package/src/utils/formatting/formatDateTime.test.ts +41 -119
  580. package/src/utils/formatting/formatDateTimeTimezone.test.ts +40 -84
  581. package/src/utils/formatting/formatNumber.test.ts +259 -0
  582. package/src/utils/formatting/formatTime.test.ts +36 -128
  583. package/src/utils/formatting/formatting.ts +1 -1
  584. package/src/utils/google-places/googlePlacesUtils.test.ts +72 -3
  585. package/src/utils/google-places/googlePlacesUtils.ts +15 -2
  586. package/src/utils/google-places/loadGoogleMapsScript.test.ts +58 -1
  587. package/src/utils/google-places/loadGoogleMapsScript.ts +2 -1
  588. package/src/utils/index.ts +52 -11
  589. package/src/utils/location/location.test.ts +18 -115
  590. package/src/utils/performance/__tests__/bundleAnalysis.test.ts +148 -0
  591. package/src/utils/performance/__tests__/performanceBenchmark.test.ts +251 -0
  592. package/src/utils/performance/__tests__/performanceBudgets.test.ts +241 -0
  593. package/src/utils/performance/bundleAnalysis.ts +16 -22
  594. package/src/utils/performance/performanceBenchmark.ts +12 -4
  595. package/src/utils/performance/performanceBudgets.ts +9 -6
  596. package/src/utils/permissions/__tests__/permissionTypes.test.ts +149 -0
  597. package/src/utils/permissions/permissionUtils.test.ts +20 -42
  598. package/src/utils/persistence/__tests__/keyDerivation.test.ts +180 -9
  599. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +164 -16
  600. package/src/utils/persistence/sensitiveFieldDetection.ts +2 -2
  601. package/src/utils/request-deduplication.ts +6 -4
  602. package/src/utils/security/auth-utils.ts +7 -7
  603. package/src/utils/security/secureDataAccess.test.ts +22 -191
  604. package/src/utils/security/secureErrors.test.ts +163 -0
  605. package/src/utils/security/secureStorage.test.ts +156 -0
  606. package/src/utils/security/secureStorage.ts +1 -1
  607. package/src/utils/security/security.test.ts +204 -0
  608. package/src/utils/security/securityMonitor.test.ts +90 -0
  609. package/src/utils/security/securityMonitor.ts +1 -1
  610. package/src/utils/storage/__tests__/config.unit.test.ts +239 -0
  611. package/src/utils/storage/__tests__/index.unit.test.ts +64 -12
  612. package/src/utils/storage/helpers.test.ts +757 -430
  613. package/src/utils/storage/helpers.ts +1 -2
  614. package/src/utils/storage/{index.ts → storageUtils.ts} +1 -36
  615. package/src/utils/storage/types.ts +2 -2
  616. package/src/utils/supabase/createBaseClient.test.ts +201 -0
  617. package/src/utils/supabase/createBaseClient.ts +27 -8
  618. package/src/utils/timezone/timezone.test.ts +25 -43
  619. package/src/utils/validation/__tests__/common.test.ts +115 -0
  620. package/src/utils/validation/__tests__/csrf.test.ts +65 -0
  621. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +27 -7
  622. package/src/utils/validation/__tests__/passwordSchema.test.ts +164 -0
  623. package/src/utils/validation/__tests__/schema.test.ts +127 -0
  624. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +76 -3
  625. package/src/utils/validation/__tests__/user.test.ts +173 -0
  626. package/src/utils/validation/__tests__/validation.test.ts +197 -0
  627. package/src/utils/validation/__tests__/validationUtils.test.ts +265 -43
  628. package/src/utils/validation/htmlSanitization.ts +27 -31
  629. package/src/utils/validation/schema.ts +6 -3
  630. package/src/utils/validation/sqlInjectionProtection.ts +2 -2
  631. package/src/vite-env.d.ts +6 -0
  632. package/dist/DataTable-DRUIgtUH.d.ts +0 -166
  633. package/dist/UnifiedAuthProvider-7SNDOWYD.js +0 -7
  634. package/dist/audit-MYQXYZFU.js +0 -3
  635. package/dist/chunk-7ILTDCL2.js +0 -80
  636. package/dist/chunk-EF2UGZWY.js +0 -611
  637. package/dist/chunk-FEJLJNWA.js +0 -181
  638. package/dist/chunk-GS5672WG.js +0 -2003
  639. package/dist/chunk-S6ZQKDY6.js +0 -62
  640. package/dist/chunk-Z2FNRKF3.js +0 -994
  641. package/dist/useToast-AyaT-x7p.d.ts +0 -68
  642. package/src/components/DataTable/components/index.ts +0 -16
  643. package/src/components/DataTable/core/index.ts +0 -1
  644. package/src/components/DataTable/hooks/index.ts +0 -13
  645. package/src/components/DataTable/utils/index.ts +0 -9
  646. package/src/components/PublicLayout/index.ts +0 -32
  647. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  648. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  649. package/src/hooks/public/index.ts +0 -36
  650. package/src/hooks/usePermissionCache.test.ts +0 -536
  651. package/src/rbac/__tests__/isSuperAdmin.real.test.ts +0 -82
  652. package/src/rbac/audit-enhanced.ts +0 -384
  653. package/src/rbac/compliance/database-validator.ts +0 -165
  654. package/src/rbac/compliance/index.ts +0 -48
  655. package/src/rbac/compliance/pattern-detector.ts +0 -553
  656. package/src/rbac/compliance/quick-fix-suggestions.ts +0 -209
  657. package/src/rbac/compliance/runtime-compliance.ts +0 -99
  658. package/src/rbac/compliance/setup-validator.ts +0 -131
  659. package/src/rbac/components/index.ts +0 -26
  660. package/src/rbac/hooks/index.ts +0 -34
  661. package/src/rbac/hooks/permissions/index.ts +0 -4
  662. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  663. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -490
  664. package/src/utils/app/appNameResolver.simple.test.ts +0 -212
  665. package/src/utils/google-places/index.ts +0 -26
  666. package/src/utils/location/index.ts +0 -16
  667. package/src/utils/storage/__tests__/helpers.unit.test.ts +0 -332
  668. package/src/utils/timezone/index.ts +0 -17
  669. package/src/utils/validation/index.ts +0 -73
package/CHANGELOG.md CHANGED
@@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ### Added
11
+ - **DataTable: Automatic label display for select fields** - Select fields with `fieldType: 'select'` and `fieldOptions` now automatically display labels (e.g., "Mobile") instead of raw values (e.g., `1`) in read mode. This eliminates the need for custom cell renderers for common select field patterns. The feature supports simple options, grouped options, type coercion, and gracefully falls back to raw values when labels aren't found. Custom cell renderers are preserved if already defined.
12
+
10
13
  ### Breaking Changes
11
14
  - **@supabase/supabase-js is now an included dependency (security enforcement)**: Moved from peer dependency to included dependency to enforce security rules. Consuming apps can no longer import `createClient` directly.
12
15
  - **Action Required**:
@@ -127,6 +127,8 @@ function checkImportPaths(consumingAppPath) {
127
127
 
128
128
  /**
129
129
  * Check test file colocation
130
+ * Only flags tests that are in the wrong location (e.g., in __tests__/ when they should be colocated).
131
+ * Does not flag missing test files - use test coverage tools for that.
130
132
  */
131
133
  function checkTestColocation(consumingAppPath) {
132
134
  const issues = [];
@@ -136,9 +138,9 @@ function checkTestColocation(consumingAppPath) {
136
138
  return issues;
137
139
  }
138
140
 
139
- // Find all source files
140
- const sourceFiles = [];
141
- function findFiles(dir) {
141
+ // Find all test files
142
+ const testFiles = [];
143
+ function findTestFiles(dir) {
142
144
  if (!fs.existsSync(dir)) return;
143
145
 
144
146
  const files = fs.readdirSync(dir);
@@ -148,49 +150,111 @@ function checkTestColocation(consumingAppPath) {
148
150
 
149
151
  if (stat.isDirectory()) {
150
152
  if (!['node_modules', 'dist', 'build', '.git'].includes(file)) {
151
- findFiles(filePath);
153
+ findTestFiles(filePath);
152
154
  }
153
- } else if (/\.(ts|tsx|js|jsx)$/.test(file) && !file.includes('.test.') && !file.includes('.spec.')) {
154
- sourceFiles.push(filePath);
155
+ } else if (/\.(ts|tsx|js|jsx)$/.test(file) && (file.includes('.test.') || file.includes('.spec.'))) {
156
+ testFiles.push(filePath);
155
157
  }
156
158
  });
157
159
  }
158
160
 
159
- findFiles(srcDir);
161
+ findTestFiles(srcDir);
160
162
 
161
- // Check if test files are colocated
162
- sourceFiles.forEach(sourceFile => {
163
- const dir = path.dirname(sourceFile);
164
- const basename = path.basename(sourceFile, path.extname(sourceFile));
165
- const ext = path.extname(sourceFile);
163
+ // Check if test files are in the wrong location
164
+ testFiles.forEach(testFile => {
165
+ const testDir = path.dirname(testFile);
166
+ const testBasename = path.basename(testFile);
166
167
 
167
- // Look for test file
168
- const testFile = path.join(dir, `${basename}.test${ext}`);
169
- const testFileTsx = path.join(dir, `${basename}.test.tsx`);
168
+ // Extract the source file name from the test file name
169
+ // e.g., "Component.test.tsx" -> "Component.tsx"
170
+ const sourceBasename = testBasename.replace(/\.(test|spec)\./, '.');
171
+ const sourceFile = path.join(testDir, sourceBasename);
170
172
 
171
- // Skip if it's a test file itself or if test file exists
172
- if (fileExists(testFile) || fileExists(testFileTsx)) {
173
- return;
174
- }
173
+ // Check if test is in a __tests__ or tests directory
174
+ const isInTestDirectory = testDir.includes('/__tests__/') || testDir.includes('/tests/') ||
175
+ testDir.endsWith('/__tests__') || testDir.endsWith('/tests');
175
176
 
176
- // Check if file is in a test directory (acceptable alternative)
177
- if (dir.includes('/__tests__/') || dir.includes('/tests/')) {
178
- return;
177
+ // If test is in a test directory, check if the source file exists in the parent directory
178
+ if (isInTestDirectory) {
179
+ // Get the parent directory (should be where the source file is)
180
+ const parentDir = path.dirname(testDir);
181
+ const expectedSourceFile = path.join(parentDir, sourceBasename);
182
+
183
+ // If source file exists in parent, flag that test should be colocated
184
+ if (fileExists(expectedSourceFile)) {
185
+ const relativePath = getRelativePath(testFile, consumingAppPath);
186
+ issues.push({
187
+ type: 'testColocation',
188
+ file: relativePath,
189
+ line: 1,
190
+ message: `Test file is in a test directory but should be colocated with source file. Move to ${parentDir}`,
191
+ severity: 'warning',
192
+ fix: `Move test file to ${parentDir} to colocate with source file`,
193
+ });
194
+ }
179
195
  }
196
+ });
197
+
198
+ return issues;
199
+ }
200
+
201
+ /**
202
+ * Check for domain-based organization (Pattern 2 - not allowed)
203
+ * Feature-based organization is the only standard
204
+ */
205
+ function checkFeatureBasedOrganization(consumingAppPath) {
206
+ const issues = [];
207
+
208
+ const srcDir = path.join(consumingAppPath, 'src');
209
+ if (!directoryExists(srcDir)) {
210
+ return issues;
211
+ }
212
+
213
+ // Check for src/domains/ directory (Pattern 2 structure - not allowed)
214
+ const domainsDir = path.join(srcDir, 'domains');
215
+ if (directoryExists(domainsDir)) {
216
+ issues.push({
217
+ type: 'organizationPattern',
218
+ file: 'src/domains',
219
+ line: 0,
220
+ message: 'Domain-based organization (src/domains/) is not allowed. Use feature-based organization instead (src/components/[feature]/, src/hooks/[feature]/, etc.)',
221
+ severity: 'error',
222
+ fix: 'Reorganize to feature-based structure: move components from src/domains/[domain]/components/ to src/components/[domain]/, hooks to src/hooks/[domain]/, etc.',
223
+ });
224
+ }
225
+
226
+ // Check components directory for type-based organization (anti-pattern)
227
+ const componentsDir = path.join(srcDir, 'components');
228
+ if (directoryExists(componentsDir)) {
229
+ const componentDirs = [];
230
+ function scanComponentsDir(dir) {
231
+ if (!fs.existsSync(dir)) return;
232
+ const entries = fs.readdirSync(dir);
233
+ entries.forEach(entry => {
234
+ const entryPath = path.join(dir, entry);
235
+ const stat = fs.statSync(entryPath);
236
+ if (stat.isDirectory()) {
237
+ componentDirs.push(entry);
238
+ }
239
+ });
240
+ }
241
+ scanComponentsDir(componentsDir);
180
242
 
181
- // For components, hooks, and utils, suggest colocation
182
- if (dir.includes('/components/') || dir.includes('/hooks/') || dir.includes('/utils/')) {
183
- const relativePath = getRelativePath(sourceFile, consumingAppPath);
243
+ // Common type-based directory names that should not exist
244
+ const typeBasedPatterns = ['buttons', 'button', 'inputs', 'input', 'cards', 'card', 'forms', 'form', 'modals', 'modal', 'dialogs', 'dialog'];
245
+ const foundTypeBased = componentDirs.filter(dir => typeBasedPatterns.includes(dir.toLowerCase()));
246
+
247
+ if (foundTypeBased.length > 0) {
184
248
  issues.push({
185
- type: 'testColocation',
186
- file: relativePath,
187
- line: 1,
188
- message: `Test file not colocated with source file. Consider creating ${path.basename(testFile)}`,
189
- severity: 'info',
190
- fix: `Create test file: ${path.basename(testFile)} in the same directory`,
249
+ type: 'organizationPattern',
250
+ file: `src/components/${foundTypeBased[0]}`,
251
+ line: 0,
252
+ message: `Components organized by type (${foundTypeBased.join(', ')}) instead of feature. Use pace-core components for UI primitives and organize app components by feature.`,
253
+ severity: 'error',
254
+ fix: `Reorganize components by feature. Use pace-core for ${foundTypeBased.join(', ')} components. Move feature-specific components to src/components/[feature]/`,
191
255
  });
192
256
  }
193
- });
257
+ }
194
258
 
195
259
  return issues;
196
260
  }
@@ -221,6 +285,7 @@ function runStandard2Audit(consumingAppPath) {
221
285
  issues.push(...checkConfigFiles(consumingAppPath));
222
286
  issues.push(...checkImportPaths(consumingAppPath));
223
287
  issues.push(...checkTestColocation(consumingAppPath));
288
+ issues.push(...checkFeatureBasedOrganization(consumingAppPath));
224
289
  issues.push(...checkSupabaseStructure(consumingAppPath));
225
290
  } catch (error) {
226
291
  return {
@@ -13,6 +13,66 @@ const path = require('path');
13
13
  const { findSourceFiles, readFileSafe, getRelativePath } = require('../utils/file-utils.cjs');
14
14
  const { getLineNumber, getCodeSnippet, isInCommentOrString, parseImports } = require('../utils/code-utils.cjs');
15
15
 
16
+ /**
17
+ * Check if a file is a test file or test utility file
18
+ * @param {string} filePath - Full path to the file
19
+ * @returns {boolean} - True if file is a test file
20
+ */
21
+ function isTestFile(filePath) {
22
+ const fileName = path.basename(filePath, path.extname(filePath));
23
+ const fileNameLower = fileName.toLowerCase();
24
+ const filePathLower = filePath.toLowerCase();
25
+
26
+ // Standard test file patterns
27
+ if (filePath.includes('.test.') || filePath.includes('.spec.')) {
28
+ return true;
29
+ }
30
+
31
+ // Files in test directories
32
+ if (filePath.includes('/test/') ||
33
+ filePath.includes('/tests/') ||
34
+ filePath.includes('__tests__') ||
35
+ filePath.includes('__test__')) {
36
+ return true;
37
+ }
38
+
39
+ // Files starting with "test" prefix
40
+ if (fileNameLower.startsWith('test')) {
41
+ return true;
42
+ }
43
+
44
+ // Test utility patterns in filename
45
+ const testUtilityPatterns = [
46
+ 'testassertion', 'testverifier', 'testhelper', 'testutility',
47
+ 'testsetup', 'testteardown', 'testmock', 'testfixture',
48
+ 'testdata', 'testutil', 'testhelper', 'testutils'
49
+ ];
50
+
51
+ if (testUtilityPatterns.some(pattern => fileNameLower.includes(pattern))) {
52
+ return true;
53
+ }
54
+
55
+ // Test utility patterns in path
56
+ const testPathPatterns = [
57
+ 'testutils', 'testhelpers', 'testassertions', 'testverifiers',
58
+ 'testsetup', 'testmocks', 'testfixtures', 'testdata'
59
+ ];
60
+
61
+ if (testPathPatterns.some(pattern => filePathLower.includes(pattern))) {
62
+ return true;
63
+ }
64
+
65
+ // Files ending with test utility suffixes
66
+ if (fileNameLower.endsWith('testutil') ||
67
+ fileNameLower.endsWith('testhelper') ||
68
+ fileNameLower.endsWith('testassertion') ||
69
+ fileNameLower.endsWith('testverifier')) {
70
+ return true;
71
+ }
72
+
73
+ return false;
74
+ }
75
+
16
76
  /**
17
77
  * Check for component boundary violations (domain logic in components)
18
78
  */
@@ -25,29 +85,37 @@ function checkComponentBoundaries(consumingAppPath) {
25
85
  }
26
86
 
27
87
  const componentFiles = findSourceFiles(srcDir).filter(file => {
28
- // Only check actual component files, not test files or utility files
29
- const isTestFile = file.includes('.test.') || file.includes('.spec.');
30
- const isUtilityFile = file.endsWith('Utils.ts') ||
31
- file.endsWith('Utils.tsx') ||
32
- file.endsWith('Helpers.ts') ||
33
- file.endsWith('Helpers.tsx') ||
34
- file.includes('testUtils') ||
35
- file.includes('testHelpers') ||
36
- file.includes('testAssertions') ||
37
- file.includes('testSetup');
38
-
39
- if (isTestFile || isUtilityFile) {
88
+ // Skip all test files
89
+ if (isTestFile(file)) {
40
90
  return false;
41
91
  }
42
92
 
43
93
  const dir = path.dirname(file);
44
94
  const isComponentDir = dir.includes('/components/') || dir.includes('/pages/');
45
- const isComponentFile = file.endsWith('.tsx') || (file.endsWith('.ts') && !isUtilityFile);
95
+ // Only check .tsx files for component boundaries (React components)
96
+ // .ts files are utilities, hooks, or test files and shouldn't be checked
97
+ const isComponentFile = file.endsWith('.tsx');
46
98
 
47
99
  return isComponentDir && isComponentFile;
48
100
  });
49
101
 
50
- componentFiles.forEach(filePath => {
102
+ // For data fetching checks, also include .ts files (to catch data fetching in hooks)
103
+ const filesForDataFetchingCheck = findSourceFiles(srcDir).filter(file => {
104
+ // Skip all test files
105
+ if (isTestFile(file)) {
106
+ return false;
107
+ }
108
+
109
+ const dir = path.dirname(file);
110
+ const isComponentDir = dir.includes('/components/') || dir.includes('/pages/');
111
+ const isComponentFile = file.endsWith('.tsx') || file.endsWith('.ts');
112
+
113
+ return isComponentDir && isComponentFile;
114
+ });
115
+
116
+ // Check for data fetching in components (should be in hooks)
117
+ // Check both .tsx and .ts files for data fetching
118
+ filesForDataFetchingCheck.forEach(filePath => {
51
119
  const content = readFileSafe(filePath);
52
120
  if (!content) {
53
121
  return;
@@ -55,7 +123,6 @@ function checkComponentBoundaries(consumingAppPath) {
55
123
 
56
124
  const relativePath = getRelativePath(filePath, consumingAppPath);
57
125
 
58
- // Check for data fetching in components (should be in hooks)
59
126
  const dataFetchingPatterns = [
60
127
  /\.from\s*\([^)]*\)\s*\.select/i,
61
128
  /\.rpc\s*\(/i,
@@ -87,8 +154,29 @@ function checkComponentBoundaries(consumingAppPath) {
87
154
  }
88
155
  }
89
156
  });
157
+ });
158
+
159
+ // Check for complex business logic in components
160
+ // Only check .tsx files (React components), not .ts files (utilities/hooks/test files)
161
+ componentFiles.forEach(filePath => {
162
+ // Safety check: explicitly skip .ts files (should already be filtered, but double-check)
163
+ if (!filePath.endsWith('.tsx')) {
164
+ return;
165
+ }
166
+
167
+ // Also skip test files as an extra safety measure
168
+ if (isTestFile(filePath)) {
169
+ return;
170
+ }
171
+
172
+ const content = readFileSafe(filePath);
173
+ if (!content) {
174
+ return;
175
+ }
176
+
177
+ const relativePath = getRelativePath(filePath, consumingAppPath);
90
178
 
91
- // Check for complex business logic in components
179
+ // All files in componentFiles are .tsx files, so we can check them directly
92
180
  // Only flag actual business logic patterns, not UI text or comments
93
181
  const businessLogicPatterns = [
94
182
  /if\s*\([^)]*permission[^)]*\)/i, // Permission checks
@@ -98,10 +186,43 @@ function checkComponentBoundaries(consumingAppPath) {
98
186
  /process\w+\s*\(/i, // Process functions (not "Processing..." text)
99
187
  ];
100
188
 
189
+ // Exclude test utility functions - functions that start with test/verify/get/create
190
+ // These are test helpers, not business logic
191
+ const isTestUtilityFunction = (match, content, index) => {
192
+ // Look backwards to extract the function name being called
193
+ const beforeMatch = content.substring(Math.max(0, index - 200), index);
194
+
195
+ // Extract identifier before the match (function name)
196
+ // Look for word characters, dots, and spaces before the match
197
+ const identifierMatch = beforeMatch.match(/(\w+)\s*$/);
198
+ if (identifierMatch) {
199
+ const functionName = identifierMatch[1];
200
+ // Check if function name starts with test utility prefixes
201
+ const testUtilityPrefixes = /^(verify|get|test|create|assert|check|expect|mock|setup|teardown)/i;
202
+ if (testUtilityPrefixes.test(functionName)) {
203
+ return true;
204
+ }
205
+ }
206
+
207
+ // Also check if it's a function definition with test utility prefix
208
+ return /(?:export\s+)?(?:async\s+)?function\s+(verify|get|test|create|assert|check|expect|mock|setup|teardown)\w*\s*\(/i.test(beforeMatch) ||
209
+ // Check if it's a const/let/var assignment
210
+ /(?:export\s+)?(?:const|let|var)\s+(verify|get|test|create|assert|check|expect|mock|setup|teardown)\w*\s*=\s*(?:async\s+)?\(/i.test(beforeMatch);
211
+ };
212
+
101
213
  // This is a heuristic - look for complex logic that should be in hooks/utils
102
214
  // Exclude common UI text patterns
103
215
  const hasUIOnlyText = /Processing\.\.\.|processing\.\.\./i.test(content);
104
- const hasComplexLogic = businessLogicPatterns.some(pattern => pattern.test(content));
216
+ const hasComplexLogic = businessLogicPatterns.some(pattern => {
217
+ const matches = content.matchAll(new RegExp(pattern.source, pattern.flags + 'g'));
218
+ for (const match of matches) {
219
+ const index = match.index;
220
+ if (!isInCommentOrString(content, index) && !isTestUtilityFunction(match, content, index)) {
221
+ return true;
222
+ }
223
+ }
224
+ return false;
225
+ });
105
226
 
106
227
  if (hasComplexLogic && !hasUIOnlyText) {
107
228
  // Check if logic is in a hook call (acceptable)
@@ -155,6 +276,11 @@ function checkApiResultUsage(consumingAppPath) {
155
276
 
156
277
  // Check for API functions that don't use ApiResult
157
278
  sourceFiles.forEach(filePath => {
279
+ // Skip test files
280
+ if (isTestFile(filePath)) {
281
+ return;
282
+ }
283
+
158
284
  const content = readFileSafe(filePath);
159
285
  if (!content) {
160
286
  return;
@@ -168,8 +294,8 @@ function checkApiResultUsage(consumingAppPath) {
168
294
  const functionName = match[1];
169
295
  const functionIndex = match.index;
170
296
 
171
- // Skip if it's a test file or hook
172
- if (filePath.includes('.test.') || functionName.startsWith('use')) {
297
+ // Skip if it's a hook
298
+ if (functionName.startsWith('use')) {
173
299
  return;
174
300
  }
175
301
 
@@ -11,7 +11,8 @@
11
11
  */
12
12
 
13
13
  const path = require('path');
14
- const { findConfigFiles, readFileSafe, getRelativePath } = require('../utils/file-utils.cjs');
14
+ const { findConfigFiles, readFileSafe, getRelativePath, findSourceFiles } = require('../utils/file-utils.cjs');
15
+ const { getLineNumber, isInCommentOrString } = require('../utils/code-utils.cjs');
15
16
 
16
17
  /**
17
18
  * Check TypeScript configuration
@@ -120,6 +121,89 @@ function checkTestCoverageConfig(consumingAppPath) {
120
121
  return issues;
121
122
  }
122
123
 
124
+ /**
125
+ * Check for excessive console logging in production code
126
+ */
127
+ function checkConsoleLogging(consumingAppPath) {
128
+ const issues = [];
129
+
130
+ const srcDir = path.join(consumingAppPath, 'src');
131
+ if (!require('fs').existsSync(srcDir)) {
132
+ return issues;
133
+ }
134
+
135
+ const sourceFiles = findSourceFiles(srcDir).filter(file => {
136
+ // Skip test files
137
+ const isTestFile = file.includes('.test.') ||
138
+ file.includes('.spec.') ||
139
+ file.includes('/test/') ||
140
+ file.includes('/tests/') ||
141
+ file.includes('__tests__') ||
142
+ file.includes('__test__') ||
143
+ path.basename(file, path.extname(file)).toLowerCase().startsWith('test');
144
+
145
+ return !isTestFile;
146
+ });
147
+
148
+ sourceFiles.forEach(filePath => {
149
+ const content = readFileSafe(filePath);
150
+ if (!content) {
151
+ return;
152
+ }
153
+
154
+ const relativePath = getRelativePath(filePath, consumingAppPath);
155
+
156
+ // Count console.log, console.debug, console.warn, console.error statements
157
+ const consolePatterns = [
158
+ { pattern: /console\.(log|debug)\s*\(/gi, name: 'console.log/debug', threshold: 3 },
159
+ { pattern: /console\.warn\s*\(/gi, name: 'console.warn', threshold: 5 },
160
+ { pattern: /console\.error\s*\(/gi, name: 'console.error', threshold: 10 }, // Errors are usually OK
161
+ ];
162
+
163
+ consolePatterns.forEach(({ pattern, name, threshold }) => {
164
+ const matches = [...content.matchAll(pattern)];
165
+ const validMatches = matches.filter(match => {
166
+ const index = match.index;
167
+ return !isInCommentOrString(content, index);
168
+ });
169
+
170
+ if (validMatches.length > threshold) {
171
+ const firstMatch = validMatches[0];
172
+ issues.push({
173
+ type: 'excessiveConsoleLogging',
174
+ file: relativePath,
175
+ line: getLineNumber(content, firstMatch.index),
176
+ message: `Excessive ${name} usage detected (${validMatches.length} instances). Consider removing debug logs or using a proper logging library.`,
177
+ severity: 'warning',
178
+ fix: `Remove or replace ${name} statements. Use a logging library or remove debug logs before production.`,
179
+ });
180
+ }
181
+ });
182
+
183
+ // Special check for DEBUG logging (common pattern)
184
+ const debugLogPattern = /console\.(log|debug)\s*\(\s*['"`]\[DEBUG\]/gi;
185
+ const debugMatches = [...content.matchAll(debugLogPattern)];
186
+ const validDebugMatches = debugMatches.filter(match => {
187
+ const index = match.index;
188
+ return !isInCommentOrString(content, index);
189
+ });
190
+
191
+ if (validDebugMatches.length > 0) {
192
+ const firstMatch = validDebugMatches[0];
193
+ issues.push({
194
+ type: 'debugConsoleLogging',
195
+ file: relativePath,
196
+ line: getLineNumber(content, firstMatch.index),
197
+ message: `Debug console logging detected (${validDebugMatches.length} instances). Debug logs should be removed or disabled in production.`,
198
+ severity: 'warning',
199
+ fix: 'Remove debug console.log statements or use environment-based logging that can be disabled in production.',
200
+ });
201
+ }
202
+ });
203
+
204
+ return issues;
205
+ }
206
+
123
207
  /**
124
208
  * Run audit for Standard 4: Code Quality
125
209
  * @param {string} consumingAppPath - Path to consuming app
@@ -131,6 +215,7 @@ function runStandard4Audit(consumingAppPath) {
131
215
  try {
132
216
  issues.push(...checkTypeScriptConfig(consumingAppPath));
133
217
  issues.push(...checkTestCoverageConfig(consumingAppPath));
218
+ issues.push(...checkConsoleLogging(consumingAppPath));
134
219
  } catch (error) {
135
220
  return {
136
221
  standard: '04-code-quality',
@@ -293,16 +293,36 @@ function checkRLSPolicies(consumingAppPath) {
293
293
  });
294
294
  }
295
295
 
296
+ // Check if function queries RLS-protected tables to determine if SECURITY DEFINER is needed
297
+ const funcBodyStart = content.indexOf('AS $$', funcStart);
298
+ let needsSecurityDefiner = false;
299
+ if (funcBodyStart !== -1) {
300
+ const funcBodyEnd = content.indexOf('$$;', funcBodyStart);
301
+ if (funcBodyEnd !== -1) {
302
+ const funcBody = content.substring(funcBodyStart, funcBodyEnd);
303
+ const rlsProtectedTables = ['rbac_organisation_roles', 'rbac_global_roles', 'rbac_event_app_roles', 'rbac_user_profiles', 'rbac_apps', 'rbac_app_pages', 'rbac_page_permissions'];
304
+ needsSecurityDefiner = rlsProtectedTables.some(table => {
305
+ const tablePattern = new RegExp(`\\b${table}\\b`, 'i');
306
+ return tablePattern.test(funcBody);
307
+ });
308
+ }
309
+ }
310
+
296
311
  if (!hasSecurityDefiner) {
297
- issues.push({
298
- type: 'rlsPolicy',
299
- file: relativePath,
300
- line: getLineNumber(content, funcStart),
301
- message: `Helper function '${funcName}' missing SECURITY DEFINER attribute. RLS helper functions must be SECURITY DEFINER to bypass RLS recursion.`,
302
- code: getCodeSnippet(content, funcStart, 0, 150),
303
- severity: 'error',
304
- fix: 'Add SECURITY DEFINER attribute to function definition.',
305
- });
312
+ if (needsSecurityDefiner) {
313
+ issues.push({
314
+ type: 'rlsPolicy',
315
+ file: relativePath,
316
+ line: getLineNumber(content, funcStart),
317
+ message: `Helper function '${funcName}' queries RLS-protected tables but missing SECURITY DEFINER attribute. REQUIRED: SECURITY DEFINER is needed to bypass RLS and avoid circular dependencies when querying RLS-protected tables from within RLS policies.`,
318
+ code: getCodeSnippet(content, funcStart, 0, 150),
319
+ severity: 'error',
320
+ fix: 'Add SECURITY DEFINER attribute to function definition. Also ensure SET search_path TO public is present.',
321
+ });
322
+ } else {
323
+ // Function doesn't query RLS-protected tables, SECURITY DEFINER might not be needed
324
+ // This is just informational, not an error
325
+ }
306
326
  }
307
327
 
308
328
  if (!hasSearchPath) {
@@ -310,12 +330,90 @@ function checkRLSPolicies(consumingAppPath) {
310
330
  type: 'rlsPolicy',
311
331
  file: relativePath,
312
332
  line: getLineNumber(content, funcStart),
313
- message: `Helper function '${funcName}' missing SET search_path TO public. Required to prevent search path injection.`,
333
+ message: `Helper function '${funcName}' missing SET search_path TO public. MANDATORY for SECURITY DEFINER functions to prevent search path hijacking attacks.`,
314
334
  code: getCodeSnippet(content, funcStart, 0, 150),
315
335
  severity: 'error',
316
- fix: 'Add SET search_path TO public to function definition.',
336
+ fix: 'Add SET search_path TO public to function definition. This is MANDATORY for SECURITY DEFINER functions to prevent search path hijacking.',
317
337
  });
318
338
  }
339
+
340
+ // Additional security checks for SECURITY DEFINER functions
341
+ if (hasSecurityDefiner) {
342
+ // Get function body to check for unqualified references
343
+ const funcBodyStart = content.indexOf('AS $$', funcStart);
344
+ if (funcBodyStart !== -1) {
345
+ const funcBodyEnd = content.indexOf('$$;', funcBodyStart);
346
+ if (funcBodyEnd !== -1) {
347
+ const funcBody = content.substring(funcBodyStart, funcBodyEnd);
348
+
349
+ // Check for unqualified table references (security risk)
350
+ // Look for FROM/JOIN without schema qualification
351
+ const unqualifiedTablePattern = /(?:FROM|JOIN)\s+([a-z_][a-z0-9_]*)\s+(?!WHERE|ON|,|$)/gi;
352
+ let tableMatch;
353
+ const rlsProtectedTables = ['rbac_organisation_roles', 'rbac_global_roles', 'rbac_event_app_roles', 'rbac_user_profiles', 'rbac_apps', 'rbac_app_pages', 'rbac_page_permissions'];
354
+
355
+ while ((tableMatch = unqualifiedTablePattern.exec(funcBody)) !== null) {
356
+ const tableName = tableMatch[1].toLowerCase();
357
+ // Check if it's a known RLS-protected table without schema qualification
358
+ if (rlsProtectedTables.some(t => t.toLowerCase() === tableName)) {
359
+ // Check if it's already schema-qualified (public.table_name)
360
+ const beforeMatch = funcBody.substring(Math.max(0, tableMatch.index - 20), tableMatch.index);
361
+ if (!/public\./i.test(beforeMatch)) {
362
+ issues.push({
363
+ type: 'rlsPolicy',
364
+ file: relativePath,
365
+ line: getLineNumber(content, funcStart + tableMatch.index),
366
+ message: `SECURITY DEFINER function '${funcName}' uses unqualified table reference '${tableName}'. MANDATORY: All table references in SECURITY DEFINER functions must be schema-qualified (e.g., public.${tableName}) to prevent search path hijacking.`,
367
+ code: getCodeSnippet(content, funcStart + tableMatch.index, 0, 100),
368
+ severity: 'error',
369
+ fix: `Schema-qualify the table reference: public.${tableName}`,
370
+ });
371
+ }
372
+ }
373
+ }
374
+
375
+ // Check if function queries RLS-protected tables (justification for SECURITY DEFINER)
376
+ const queriesRLSProtected = rlsProtectedTables.some(table => {
377
+ const tablePattern = new RegExp(`\\b${table}\\b`, 'i');
378
+ return tablePattern.test(funcBody);
379
+ });
380
+
381
+ // Check if function has any table queries at all
382
+ const hasTableQueries = /(?:FROM|JOIN|INTO|UPDATE)\s+\w+/i.test(funcBody);
383
+
384
+ if (!queriesRLSProtected && hasTableQueries) {
385
+ // Function has SECURITY DEFINER but doesn't query RLS-protected tables
386
+ // This might be okay if it needs elevated privileges, but should be documented
387
+ const hasComment = /COMMENT\s+ON\s+FUNCTION.*SECURITY\s+DEFINER/i.test(content.substring(funcStart, funcStart + 2000));
388
+ if (!hasComment) {
389
+ issues.push({
390
+ type: 'rlsPolicy',
391
+ file: relativePath,
392
+ line: getLineNumber(content, funcStart),
393
+ message: `SECURITY DEFINER function '${funcName}' does not query RLS-protected tables. If SECURITY DEFINER is needed for elevated privileges, document why in a COMMENT. Otherwise, consider removing SECURITY DEFINER if not needed.`,
394
+ code: getCodeSnippet(content, funcStart, 0, 200),
395
+ severity: 'warning',
396
+ fix: 'Add COMMENT ON FUNCTION explaining why SECURITY DEFINER is needed, or remove SECURITY DEFINER if not required.',
397
+ });
398
+ }
399
+ } else if (queriesRLSProtected && !hasComment) {
400
+ // Function queries RLS-protected tables but doesn't document why SECURITY DEFINER is needed
401
+ const hasComment = /COMMENT\s+ON\s+FUNCTION/i.test(content.substring(funcStart, funcStart + 2000));
402
+ if (!hasComment) {
403
+ issues.push({
404
+ type: 'rlsPolicy',
405
+ file: relativePath,
406
+ line: getLineNumber(content, funcStart),
407
+ message: `SECURITY DEFINER function '${funcName}' queries RLS-protected tables but lacks documentation. REQUIRED: Add COMMENT ON FUNCTION explaining why SECURITY DEFINER is needed (to avoid circular RLS dependencies).`,
408
+ code: getCodeSnippet(content, funcStart, 0, 200),
409
+ severity: 'warning',
410
+ fix: 'Add COMMENT ON FUNCTION documenting that SECURITY DEFINER is required to avoid circular RLS dependencies when querying RLS-protected tables.',
411
+ });
412
+ }
413
+ }
414
+ }
415
+ }
416
+ }
319
417
  }
320
418
  }
321
419
  } catch (error) {