@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,340 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Error Handling Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/ErrorHandling
7
- *
8
- * Checks for:
9
- * - Missing error boundaries
10
- * - Unhandled promise rejections
11
- * - Missing error handling in async functions
12
- * - Silent error swallowing
13
- * - Missing error states in components
14
- */
15
-
16
- const fs = require('fs');
17
- const path = require('path');
18
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
19
-
20
- const errorHandlingCheck = {
21
- name: 'error-handling',
22
- description: 'Error handling patterns (error boundaries, async error handling)',
23
- severity: 'warning',
24
-
25
- async run(context) {
26
- const { projectRoot, files } = context;
27
- const issues = [];
28
- const warnings = [];
29
- const suggestions = [];
30
-
31
- if (!files || files.length === 0) {
32
- return { issues, warnings, suggestions };
33
- }
34
-
35
- // Skip if this is the pace-core repository itself
36
- // Detect pace-core repository by checking if packages/core exists
37
- const packagesCorePath = path.join(projectRoot, 'packages', 'core');
38
- const isPaceCoreRepository = fs.existsSync(packagesCorePath);
39
-
40
- // Check for ErrorBoundary usage in main app file
41
- let hasErrorBoundary = false;
42
- const mainFiles = ['main.tsx', 'main.ts', 'App.tsx', 'App.ts', 'index.tsx', 'index.ts'];
43
-
44
- // First, specifically check the main app file for ErrorBoundary usage
45
- // This must be done before the general file loop to ensure we check the actual main file
46
- // Previously, the check would skip src/ files (thinking they were demo apps) and only
47
- // check if ErrorBoundary appeared anywhere in the codebase. Now we specifically check
48
- // the main.tsx file for proper ErrorBoundary import and JSX usage patterns.
49
- if (!isPaceCoreRepository) {
50
- const mainFile = mainFiles.find(file => {
51
- const filePath = path.join(projectRoot, 'src', file);
52
- return fs.existsSync(filePath);
53
- });
54
-
55
- if (mainFile) {
56
- const mainFilePath = path.join(projectRoot, 'src', mainFile);
57
- try {
58
- const mainContent = fs.readFileSync(mainFilePath, 'utf8');
59
-
60
- // Check for ErrorBoundary import from pace-core
61
- // Matches: import { ErrorBoundary } from '@jmruthers/pace-core'
62
- // Matches: import { ..., ErrorBoundary, ... } from '@jmruthers/pace-core'
63
- // Matches: import { ErrorBoundary } from '@jmruthers/pace-core/components'
64
- const hasErrorBoundaryImport = /import\s+[^'"]*ErrorBoundary[^'"]*from\s+['"]@jmruthers\/pace-core/.test(mainContent);
65
-
66
- // Check for ErrorBoundary JSX usage
67
- // Matches: <ErrorBoundary ...> or <ErrorBoundary>
68
- const hasErrorBoundaryJSX = /<ErrorBoundary[\s>]/.test(mainContent);
69
-
70
- // Check if ErrorBoundary wraps the render call or app component
71
- // Pattern 1: createRoot(...).render(<ErrorBoundary ...)
72
- // Pattern 2: render(<ErrorBoundary ...)
73
- // Pattern 3: <ErrorBoundary ...> wrapping App component or createRoot call
74
- const hasErrorBoundaryInRender = /createRoot\s*\([^)]*\)\s*\.\s*render\s*\(\s*<ErrorBoundary/.test(mainContent) ||
75
- /\.render\s*\(\s*<ErrorBoundary/.test(mainContent) ||
76
- /<ErrorBoundary[\s\S]{0,500}?<App[\s>]/.test(mainContent) ||
77
- /<ErrorBoundary[\s\S]{0,500}?createRoot/.test(mainContent);
78
-
79
- // ErrorBoundary is present if it's imported AND used in JSX
80
- // We check both JSX usage and render wrapping to catch all valid patterns
81
- if (hasErrorBoundaryImport && (hasErrorBoundaryJSX || hasErrorBoundaryInRender)) {
82
- hasErrorBoundary = true;
83
- }
84
- } catch (error) {
85
- // If we can't read the main file, continue with other checks
86
- }
87
- }
88
- }
89
-
90
- for (const filePath of files) {
91
- try {
92
- const content = fs.readFileSync(filePath, 'utf8');
93
- const relativePath = getRelativePath(filePath, projectRoot);
94
- const normalizedPath = relativePath.replace(/\\/g, '/');
95
- const fileName = path.basename(relativePath);
96
-
97
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
98
- // Note: We DO check packages/core/ files because error handling issues (missing try/catch, missing .catch()) are real issues that should be fixed
99
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
100
- if (isRootSrc) {
101
- continue; // Skip demo app files
102
- }
103
-
104
- // Skip scripts directory - utility scripts don't need error handling validation
105
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
106
- if (isScript) {
107
- continue; // Skip script files
108
- }
109
-
110
- // Check for unhandled promise rejections
111
- const asyncFunctionPattern = /(async\s+function|const\s+\w+\s*=\s*async|export\s+async\s+function)/g;
112
- let asyncMatch;
113
- while ((asyncMatch = asyncFunctionPattern.exec(content)) !== null) {
114
- const functionStart = asyncMatch.index;
115
- const beforeAsync = content.substring(Math.max(0, functionStart - 100), functionStart);
116
- const afterAsync = content.substring(functionStart, Math.min(content.length, functionStart + 1000));
117
-
118
- // Check if function has try/catch
119
- const hasTryCatch = /try\s*\{/.test(afterAsync);
120
-
121
- // Check for await calls
122
- const hasAwait = /await\s+/.test(afterAsync);
123
-
124
- // Check if this is an exported library function (designed to throw errors for callers to handle)
125
- // Look for "export" before the async function declaration
126
- const isExportedLibraryFunction = /export\s+(async\s+function|function)/.test(beforeAsync + asyncMatch[0]) ||
127
- asyncMatch[0].includes('export');
128
-
129
- // Skip pace-core files - library code has different error handling patterns
130
- // Exported functions are designed to throw errors for callers to handle
131
- // Internal utility functions may also intentionally propagate errors
132
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
133
-
134
- if (hasAwait && !hasTryCatch && !isExportedLibraryFunction && !isPaceCorePackage) {
135
- warnings.push({
136
- type: 'unhandled-async',
137
- file: relativePath,
138
- line: getLineNumber(content, asyncMatch.index),
139
- message: 'Async function with await calls but no try/catch error handling',
140
- recommendation: 'Wrap await calls in try/catch blocks to handle errors gracefully'
141
- });
142
- }
143
- }
144
-
145
- // Check for .then() without .catch()
146
- // Look for .then() and check if there's a .catch() later in the chain (not just immediately after)
147
- const thenPattern = /\.then\s*\([^)]*\)/g;
148
- let thenMatch;
149
- while ((thenMatch = thenPattern.exec(content)) !== null) {
150
- // Check if there's a .catch() after this .then() in the promise chain
151
- // Look ahead up to 500 chars (reasonable for a promise chain)
152
- const afterThen = content.substring(thenMatch.index, Math.min(content.length, thenMatch.index + 500));
153
-
154
- // Check if there's a .catch() in the chain
155
- // Also check for .then().catch() pattern
156
- const hasCatch = /\.catch\s*\(/.test(afterThen);
157
-
158
- // Check if the .then() handler has try/catch inside it (valid pattern: .then(async () => { try { ... } catch { ... } }))
159
- const hasTryCatchInHandler = /\.then\s*\(\s*async\s*\([^)]*\)\s*=>\s*\{[^}]*try\s*\{/.test(afterThen);
160
-
161
- // Also check if the .then() itself handles errors (returns error object)
162
- const thenBody = thenMatch[0];
163
- const handlesErrorInThen = /error|Error|catch/.test(thenBody);
164
-
165
- // Skip pace-core files - library code has complex patterns that are hard to detect accurately
166
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
167
-
168
- if (!hasCatch && !handlesErrorInThen && !hasTryCatchInHandler && !isPaceCorePackage) {
169
- warnings.push({
170
- type: 'unhandled-promise',
171
- file: relativePath,
172
- line: getLineNumber(content, thenMatch.index),
173
- message: 'Promise chain with .then() but no .catch() handler',
174
- recommendation: 'Add .catch() handler to handle promise rejections. The .catch() can come after the .then() in the chain.'
175
- });
176
- }
177
- }
178
-
179
- // Check for console.error without proper error handling
180
- const consoleErrorPattern = /console\.error\s*\([^)]*\)/g;
181
- let consoleMatch;
182
- while ((consoleMatch = consoleErrorPattern.exec(content)) !== null) {
183
- // Skip console.error in comments/JSDoc (example code)
184
- const beforeMatch = content.substring(Math.max(0, consoleMatch.index - 500), consoleMatch.index);
185
- const afterMatch = content.substring(consoleMatch.index, Math.min(content.length, consoleMatch.index + 50));
186
-
187
- // Get the line number to check if we're in a comment block
188
- const errorLineNum = getLineNumber(content, consoleMatch.index);
189
- const lines = content.split('\n');
190
- const errorLine = lines[errorLineNum - 1]; // Line numbers are 1-indexed
191
-
192
- // Check if the line starts with * (JSDoc comment block) or // (single line comment)
193
- const isInCommentLine = /^\s*\*|^\s*\/\//.test(errorLine);
194
-
195
- // Check if we're inside a /* ... */ or /** ... */ block
196
- // Find the last /* or /** before this position, and check if */ comes after
197
- const lastCommentStart = beforeMatch.lastIndexOf('/*');
198
- const lastCommentEndBefore = beforeMatch.lastIndexOf('*/');
199
- const firstCommentEndAfter = afterMatch.indexOf('*/');
200
- // We're in a comment block if there's a /* before and no */ before it (or */ is after)
201
- const isInCommentBlock = lastCommentStart !== -1 &&
202
- (lastCommentStart > lastCommentEndBefore || firstCommentEndAfter !== -1);
203
-
204
- // Check if it's in a comment (JSDoc example or comment block)
205
- if (isInCommentLine || isInCommentBlock) {
206
- continue; // Skip JSDoc examples and comment blocks
207
- }
208
-
209
- // Skip example files - these are demonstration code, not production code
210
- const isExampleFile = normalizedPath.includes('/examples/') || normalizedPath.includes('Example.tsx') || normalizedPath.includes('Example.ts');
211
- if (isExampleFile) {
212
- continue; // Skip example files
213
- }
214
-
215
- // Skip logger utility files - these ARE the error handling mechanism
216
- const isLoggerUtility = normalizedPath.includes('logger') ||
217
- normalizedPath.includes('debugLogger') ||
218
- normalizedPath.includes('rbac/config.ts'); // RBAC config is a logger setup
219
- if (isLoggerUtility) {
220
- continue; // Skip logger utilities
221
- }
222
-
223
- // Skip ESLint rule files - these are tooling, not application code
224
- const isEslintRule = normalizedPath.includes('eslint-rules') || normalizedPath.includes('eslint.config');
225
- if (isEslintRule) {
226
- continue; // Skip ESLint rules
227
- }
228
-
229
- // Skip performance monitoring utilities - these are informational logging
230
- const isPerformanceUtility = normalizedPath.includes('performance') &&
231
- (normalizedPath.includes('performanceBudgets') || normalizedPath.includes('performanceBenchmark'));
232
- if (isPerformanceUtility) {
233
- continue; // Skip performance monitoring
234
- }
235
-
236
- // Check if it's just logging without handling
237
- // Also check after the console.error to see if error state is set or error is returned
238
- const afterError = content.substring(consoleMatch.index, Math.min(content.length, consoleMatch.index + 200));
239
- const hasErrorHandling = beforeMatch.includes('throw') ||
240
- beforeMatch.includes('return') ||
241
- beforeMatch.includes('catch') ||
242
- afterError.includes('throw') || // Check after as well (e.g., console.error then throw)
243
- afterError.includes('setError') ||
244
- afterError.includes('error =') ||
245
- afterError.includes('onError') ||
246
- afterError.includes('onUploadError');
247
-
248
- if (!hasErrorHandling) {
249
- suggestions.push({
250
- type: 'error-logging-only',
251
- file: relativePath,
252
- line: getLineNumber(content, consoleMatch.index),
253
- message: 'Error is logged but may not be handled properly',
254
- recommendation: 'Ensure errors are properly handled (thrown, returned, or displayed to users)'
255
- });
256
- }
257
- }
258
-
259
- // Check for missing error states in components using pace-core hooks
260
- // Only check React component files
261
- if (filePath.match(/\.(tsx|jsx)$/)) {
262
- const paceCoreHooks = ['useUnifiedAuth', 'useOrganisations', 'useEvents', 'useSecureSupabase'];
263
- paceCoreHooks.forEach(hookName => {
264
- if (content.includes(hookName)) {
265
- const hookPattern = new RegExp(`const\\s+[^=]+=\\s+${hookName}\\s*\\(`, 'g');
266
- let hookMatch;
267
- while ((hookMatch = hookPattern.exec(content)) !== null) {
268
- // Check the entire component, not just 500 chars after hook
269
- // React's Rules of Hooks require all hooks to be called before conditional returns,
270
- // so error handling may occur later in the component
271
- const hookLine = getLineNumber(content, hookMatch.index);
272
- const lines = content.split('\n');
273
- const hookLineIndex = hookLine - 1;
274
-
275
- // Get the rest of the component after this hook
276
- const afterHookContent = lines.slice(hookLineIndex).join('\n');
277
-
278
- // Check if error is destructured from the hook
279
- const hookCallLine = lines[hookLineIndex];
280
- const hasErrorDestructured = /(error|Error|authError|orgError)/.test(hookCallLine);
281
-
282
- // For useSecureSupabase, check for null checks (it returns null on error)
283
- const isSecureSupabase = hookName === 'useSecureSupabase';
284
- const hasNullCheck = isSecureSupabase && /secureSupabase\s*===?\s*null|!secureSupabase/.test(afterHookContent);
285
-
286
- // Check for error handling patterns in the entire component:
287
- // 1. Component-level error checks with early returns: if (error) return <ErrorUI />
288
- // 2. useEffect error handlers: useEffect(() => { if (error) ... }, [error])
289
- // 3. Null checks for useSecureSupabase: if (secureSupabase === null) ...
290
- // 4. Error passed to error handling utilities
291
-
292
- const hasComponentLevelErrorCheck = /if\s*\(\s*(error|authError|orgError|rbacError)/.test(afterHookContent);
293
- const hasUseEffectErrorHandler = /useEffect\s*\([^)]*\([^)]*\)\s*=>\s*\{[^}]*\b(error|authError|orgError|rbacError)\b[^}]*\}/.test(afterHookContent);
294
- const hasErrorInDeps = /useEffect\s*\([^)]*,\s*\[[^\]]*\b(error|authError|orgError|rbacError)\b/.test(afterHookContent);
295
- const hasErrorHandling = /if\s*\(\s*(error|authError|orgError|rbacError)|(error|authError|orgError|rbacError)\s*\?|catch/.test(afterHookContent);
296
- const hasErrorUtility = /handleSupabaseError|handleError|toast.*error|showError/.test(afterHookContent);
297
-
298
- // Only flag if error is destructured but not handled anywhere
299
- if (hasErrorDestructured && !hasComponentLevelErrorCheck && !hasUseEffectErrorHandler &&
300
- !hasErrorInDeps && !hasErrorHandling && !hasErrorUtility && !hasNullCheck) {
301
- warnings.push({
302
- type: 'unhandled-hook-error',
303
- file: relativePath,
304
- line: hookLine,
305
- message: `${hookName} may return an error that is not handled`,
306
- recommendation: 'Check for error state and handle it appropriately. You can handle errors via: (1) Component-level checks after all hooks: if (error) return <ErrorUI />, (2) useEffect hooks that monitor error states, or (3) For useSecureSupabase, null checks: if (secureSupabase === null) ...'
307
- });
308
- }
309
- }
310
- }
311
- });
312
- }
313
- } catch (error) {
314
- // Skip files with errors
315
- }
316
- }
317
-
318
- // Check if ErrorBoundary is used in main app file
319
- // Skip this check if this is the pace-core repository (root src/ is a demo app)
320
- if (!hasErrorBoundary && !isPaceCoreRepository) {
321
- const mainFile = mainFiles.find(file => {
322
- const filePath = path.join(projectRoot, 'src', file);
323
- return fs.existsSync(filePath);
324
- });
325
-
326
- if (mainFile) {
327
- suggestions.push({
328
- type: 'missing-error-boundary',
329
- file: `src/${mainFile}`,
330
- message: 'No ErrorBoundary found in main app file',
331
- recommendation: 'Wrap your app with ErrorBoundary from @jmruthers/pace-core to catch and handle React errors gracefully'
332
- });
333
- }
334
- }
335
-
336
- return { issues, warnings, suggestions };
337
- }
338
- };
339
-
340
- module.exports = errorHandlingCheck;
@@ -1,172 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Form Validation Check Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Forms
7
- *
8
- * Checks for:
9
- * - Missing form validation
10
- * - Incorrect useZodForm usage
11
- * - Missing error messages
12
- * - Form submission without loading states
13
- */
14
-
15
- const fs = require('fs');
16
- const { getRelativePath, getLineNumber } = require('../utils.cjs');
17
-
18
- const formsCheck = {
19
- name: 'forms',
20
- description: 'Form validation patterns (useZodForm, error handling)',
21
- severity: 'warning',
22
-
23
- async run(context) {
24
- const { projectRoot, files } = context;
25
- const issues = [];
26
- const warnings = [];
27
- const suggestions = [];
28
-
29
- if (!files || files.length === 0) {
30
- return { issues, warnings, suggestions };
31
- }
32
-
33
- for (const filePath of files) {
34
- try {
35
- // Only check React component files
36
- if (!filePath.match(/\.(tsx|jsx)$/)) {
37
- continue;
38
- }
39
-
40
- const content = fs.readFileSync(filePath, 'utf8');
41
- const relativePath = getRelativePath(filePath, projectRoot);
42
- const normalizedPath = relativePath.replace(/\\/g, '/');
43
-
44
- // Skip pace-core package files - forms check is for consuming applications, not the library itself
45
- // Note: Library components (like Form.tsx, LoginForm.tsx, Select.tsx) ARE the Form components
46
- // They don't need to use themselves - they provide the form functionality
47
- const isPaceCorePackage = normalizedPath.includes('packages/core/') || normalizedPath.startsWith('packages/core/');
48
- if (isPaceCorePackage) {
49
- continue; // Skip library files (including examples)
50
- }
51
-
52
- // Skip root-level src directory - in pace-core repository, this is a demo/showcase app
53
- const isRootSrc = normalizedPath.startsWith('src/') && !normalizedPath.includes('packages/');
54
- if (isRootSrc) {
55
- continue; // Skip demo app files
56
- }
57
-
58
- // Skip scripts directory - utility scripts don't need form validation
59
- const isScript = normalizedPath.startsWith('scripts/') || normalizedPath.includes('/scripts/');
60
- if (isScript) {
61
- continue; // Skip script files
62
- }
63
-
64
- // Check for form elements
65
- const hasForm = /<form|Form|useZodForm/.test(content);
66
- if (!hasForm) {
67
- continue;
68
- }
69
-
70
- // Check for useZodForm usage
71
- if (content.includes('useZodForm')) {
72
- const zodFormPattern = /const\s+[^=]+=\s+useZodForm\s*\(/g;
73
- let formMatch;
74
- while ((formMatch = zodFormPattern.exec(content)) !== null) {
75
- const afterForm = content.substring(formMatch.index, Math.min(content.length, formMatch.index + 500));
76
-
77
- // Check if schema is provided
78
- if (!afterForm.includes('schema:') && !afterForm.includes('schema =')) {
79
- warnings.push({
80
- type: 'missing-form-schema',
81
- file: relativePath,
82
- line: getLineNumber(content, formMatch.index),
83
- message: 'useZodForm called without schema',
84
- recommendation: 'Provide a Zod schema to useZodForm for form validation'
85
- });
86
- }
87
-
88
- // Check if form errors are displayed
89
- const hasErrorDisplay = /formState\.errors|errors\[|\.error/.test(content);
90
- if (!hasErrorDisplay) {
91
- suggestions.push({
92
- type: 'missing-form-errors',
93
- file: relativePath,
94
- line: getLineNumber(content, formMatch.index),
95
- message: 'Form may not be displaying validation errors',
96
- recommendation: 'Display form errors to users using formState.errors or FormField error prop'
97
- });
98
- }
99
- }
100
- }
101
-
102
- // Check for form submission without loading state
103
- const onSubmitPattern = /onSubmit\s*=\s*\{[^}]*async/g;
104
- let submitMatch;
105
- while ((submitMatch = onSubmitPattern.exec(content)) !== null) {
106
- const afterSubmit = content.substring(submitMatch.index, Math.min(content.length, submitMatch.index + 1000));
107
-
108
- // Check if there's a loading state
109
- const hasLoadingState = /isLoading|loading|isSubmitting|submitting/.test(afterSubmit);
110
- const hasDisabled = /disabled\s*=\s*\{/.test(content);
111
-
112
- if (!hasLoadingState && !hasDisabled) {
113
- suggestions.push({
114
- type: 'missing-submit-loading',
115
- file: relativePath,
116
- line: getLineNumber(content, submitMatch.index),
117
- message: 'Form submission without loading state',
118
- recommendation: 'Add loading state during form submission to prevent double-submission and provide user feedback'
119
- });
120
- }
121
- }
122
-
123
- // Check for native form elements that should use pace-core Form
124
- const nativeFormPattern = /<form[^>]*>/g;
125
- let nativeMatch;
126
- while ((nativeMatch = nativeFormPattern.exec(content)) !== null) {
127
- const beforeMatch = content.substring(Math.max(0, nativeMatch.index - 100), nativeMatch.index);
128
- const usesPaceCoreForm = beforeMatch.includes('from \'@jmruthers/pace-core\'') ||
129
- content.includes('<Form');
130
-
131
- if (!usesPaceCoreForm) {
132
- suggestions.push({
133
- type: 'native-form-element',
134
- file: relativePath,
135
- line: getLineNumber(content, nativeMatch.index),
136
- message: 'Native <form> element detected',
137
- recommendation: 'Use Form component from @jmruthers/pace-core for consistent styling and validation'
138
- });
139
- }
140
- }
141
-
142
- // Check for input elements without validation
143
- const inputPattern = /<input[^>]*>/g;
144
- let inputMatch;
145
- while ((inputMatch = inputPattern.exec(content)) !== null) {
146
- const inputTag = inputMatch[0];
147
- const hasFormField = content.substring(Math.max(0, inputMatch.index - 200), inputMatch.index).includes('FormField');
148
- const hasValidation = inputTag.includes('required') ||
149
- inputTag.includes('pattern') ||
150
- content.substring(Math.max(0, inputMatch.index - 200), inputMatch.index).includes('register');
151
-
152
- if (!hasFormField && !hasValidation && !inputTag.includes('type="hidden"')) {
153
- suggestions.push({
154
- type: 'unvalidated-input',
155
- file: relativePath,
156
- line: getLineNumber(content, inputMatch.index),
157
- message: 'Input element without validation',
158
- recommendation: 'Use FormField from @jmruthers/pace-core or add validation to form inputs'
159
- });
160
- }
161
- }
162
-
163
- } catch (error) {
164
- // Skip files with errors
165
- }
166
- }
167
-
168
- return { issues, warnings, suggestions };
169
- }
170
- };
171
-
172
- module.exports = formsCheck;
@@ -1,68 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * Heuristic Checks Module
5
- * @package @jmruthers/pace-core
6
- * @module Audit/Checks/Heuristics
7
- *
8
- * Code quality heuristics including:
9
- * - Large files
10
- * - God objects (files with many exports)
11
- */
12
-
13
- const fs = require('fs');
14
- const path = require('path');
15
-
16
- const heuristicsCheck = {
17
- name: 'heuristics',
18
- description: 'Code quality heuristics (large files, god objects)',
19
- severity: 'suggestion',
20
-
21
- async run(context) {
22
- const { projectRoot, files } = context;
23
- const suggestions = [];
24
-
25
- if (!files || files.length === 0) {
26
- return { issues: [], warnings: [], suggestions: [] };
27
- }
28
-
29
- const maxLines = 1000;
30
-
31
- // Check for large files
32
- for (const filePath of files) {
33
- try {
34
- const content = fs.readFileSync(filePath, 'utf8');
35
- const lines = content.split('\n').length;
36
-
37
- if (lines > maxLines) {
38
- const relativePath = path.relative(projectRoot, filePath);
39
- suggestions.push({
40
- type: 'large-file',
41
- file: relativePath,
42
- message: `File has ${lines} lines, consider splitting into smaller modules`,
43
- recommendation: `Split this file into smaller, focused modules (target: <${maxLines} lines)`
44
- });
45
- }
46
-
47
- // Check for god objects (files with many exports)
48
- const exportCount = (content.match(/export\s+(const|function|class|interface|type)/g) || []).length;
49
-
50
- if (exportCount > 10) {
51
- const relativePath = path.relative(projectRoot, filePath);
52
- suggestions.push({
53
- type: 'god-object',
54
- file: relativePath,
55
- message: `File exports ${exportCount} items, consider splitting into smaller modules`,
56
- recommendation: `Split this file into smaller modules, each with a focused responsibility (target: <10 exports per file)`
57
- });
58
- }
59
- } catch (error) {
60
- // Skip files we can't read
61
- }
62
- }
63
-
64
- return { issues: [], warnings: [], suggestions };
65
- }
66
- };
67
-
68
- module.exports = heuristicsCheck;