@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -0,0 +1,348 @@
1
+ /**
2
+ * General compliance rules
3
+ * @package @jmruthers/pace-core
4
+ * @module ESLintRules/rules/compliance
5
+ */
6
+
7
+ const path = require('path');
8
+ const { getPaceCoreComponents, getPaceCoreHooks, getPaceCoreUtils } = require('../utils/manifest-loader.cjs');
9
+ const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
10
+
11
+ module.exports = {
12
+ rules: {
13
+ /**
14
+ * Prefer pace-core components over native HTML elements or custom implementations
15
+ */
16
+ 'prefer-pace-core-components': {
17
+ meta: {
18
+ type: 'suggestion',
19
+ docs: {
20
+ description: 'Suggest using pace-core components instead of native HTML elements',
21
+ category: 'Best Practices',
22
+ recommended: true
23
+ },
24
+ hasSuggestions: true,
25
+ messages: {
26
+ preferButton: "Use 'Button' component from '@jmruthers/pace-core' instead of <button>",
27
+ preferInput: "Use 'Input' component from '@jmruthers/pace-core' instead of <input>",
28
+ preferTextarea: "Use 'Textarea' component from '@jmruthers/pace-core' instead of <textarea>",
29
+ preferLabel: "Use 'Label' component from '@jmruthers/pace-core' instead of <label>",
30
+ preferForm: "Use 'Form' component from '@jmruthers/pace-core' instead of custom form implementation"
31
+ }
32
+ },
33
+ create(context) {
34
+ const filename = context.getFilename();
35
+
36
+ // Exclude pace-core source files - these rules are for consuming apps
37
+ if (isPaceCoreSourceFile(filename)) {
38
+ return {};
39
+ }
40
+
41
+ const paceCoreComponents = getPaceCoreComponents();
42
+
43
+ return {
44
+ JSXOpeningElement(node) {
45
+ const elementName = node.name.name;
46
+
47
+ if (!elementName) return;
48
+
49
+ // Only flag lowercase native HTML elements, not capitalized components
50
+ // Native HTML: <button>, <input>, <label>, <textarea>
51
+ // Components: <Button>, <Input>, <Label>, <Textarea>
52
+ const isNativeHTMLElement = elementName === elementName.toLowerCase();
53
+
54
+ if (!isNativeHTMLElement) {
55
+ // This is a capitalized component, not a native HTML element
56
+ return;
57
+ }
58
+
59
+ // Check for native HTML elements that have pace-core alternatives
60
+ const nativeToPaceCore = {
61
+ 'button': 'Button',
62
+ 'input': 'Input',
63
+ 'textarea': 'Textarea',
64
+ 'label': 'Label'
65
+ };
66
+
67
+ if (nativeToPaceCore[elementName]) {
68
+ const paceCoreComponent = nativeToPaceCore[elementName];
69
+ if (paceCoreComponents.includes(paceCoreComponent)) {
70
+ context.report({
71
+ node,
72
+ messageId: `prefer${paceCoreComponent}`,
73
+ suggest: [{
74
+ desc: `Import and use ${paceCoreComponent} from pace-core`,
75
+ fix(fixer) {
76
+ // This is a complex fix, so we'll just report
77
+ return null;
78
+ }
79
+ }]
80
+ });
81
+ }
82
+ }
83
+ }
84
+ };
85
+ }
86
+ },
87
+
88
+ /**
89
+ * Detect custom hooks that duplicate pace-core functionality
90
+ */
91
+ 'prefer-pace-core-hooks': {
92
+ meta: {
93
+ type: 'suggestion',
94
+ docs: {
95
+ description: 'Suggest using pace-core hooks instead of custom implementations',
96
+ category: 'Best Practices',
97
+ recommended: true
98
+ },
99
+ messages: {
100
+ preferPaceCoreHook: "Consider using '{{hook}}' from '@jmruthers/pace-core' instead of custom hook '{{customHook}}'"
101
+ }
102
+ },
103
+ create(context) {
104
+ const filename = context.getFilename();
105
+
106
+ // Exclude pace-core source files - these rules are for consuming apps
107
+ if (isPaceCoreSourceFile(filename)) {
108
+ return {};
109
+ }
110
+
111
+ const paceCoreHooks = getPaceCoreHooks();
112
+ const hookPatterns = {
113
+ 'useToast': ['useToast', 'useNotification', 'useSnackbar'],
114
+ 'useDebounce': ['useDebounce', 'useDebounced'],
115
+ 'useAuth': ['useAuth', 'useAuthentication', 'useUser'],
116
+ 'useFile': ['useFile', 'useFileUpload', 'useFileReference'],
117
+ 'useForm': ['useForm', 'useZodForm'],
118
+ 'useTable': ['useTable', 'useDataTable']
119
+ };
120
+
121
+ return {
122
+ FunctionDeclaration(node) {
123
+ const functionName = node.id?.name;
124
+ if (!functionName || !functionName.startsWith('use')) return;
125
+
126
+ // Check if this looks like a hook that pace-core provides
127
+ for (const [paceCoreHook, patterns] of Object.entries(hookPatterns)) {
128
+ if (paceCoreHooks.includes(paceCoreHook)) {
129
+ for (const pattern of patterns) {
130
+ if (functionName.toLowerCase().includes(pattern.toLowerCase().replace('use', ''))) {
131
+ context.report({
132
+ node: node.id,
133
+ messageId: 'preferPaceCoreHook',
134
+ data: {
135
+ hook: paceCoreHook,
136
+ customHook: functionName
137
+ }
138
+ });
139
+ return;
140
+ }
141
+ }
142
+ }
143
+ }
144
+ }
145
+ };
146
+ }
147
+ },
148
+
149
+ /**
150
+ * Detect utility functions that duplicate pace-core functionality
151
+ */
152
+ 'prefer-pace-core-utils': {
153
+ meta: {
154
+ type: 'suggestion',
155
+ docs: {
156
+ description: 'Suggest using pace-core utilities instead of custom implementations',
157
+ category: 'Best Practices',
158
+ recommended: true
159
+ },
160
+ messages: {
161
+ preferPaceCoreUtil: "Consider using '{{util}}' from '@jmruthers/pace-core' instead of custom function '{{customUtil}}'"
162
+ }
163
+ },
164
+ create(context) {
165
+ const filename = context.getFilename();
166
+
167
+ // Exclude pace-core source files - these rules are for consuming apps
168
+ if (isPaceCoreSourceFile(filename)) {
169
+ return {};
170
+ }
171
+
172
+ const paceCoreUtils = getPaceCoreUtils();
173
+ const utilPatterns = {
174
+ 'formatDate': ['formatDate', 'formatDateTime', 'dateFormat'],
175
+ 'formatCurrency': ['formatCurrency', 'formatMoney', 'currencyFormat'],
176
+ 'formatNumber': ['formatNumber', 'numberFormat'],
177
+ 'cn': ['cn', 'classNames', 'clsx', 'mergeClasses'],
178
+ 'validateUserInput': ['validateInput', 'validateUser', 'validateUserInput'],
179
+ 'sanitizeUserInput': ['sanitize', 'sanitizeInput', 'sanitizeUser']
180
+ };
181
+
182
+ // Patterns that should NOT trigger validateUserInput warnings
183
+ // These are for API/config validation, not user input validation
184
+ const excludePatterns = [
185
+ 'validateApi',
186
+ 'validateRequest',
187
+ 'validateConfig',
188
+ 'validateKey',
189
+ 'validateToken',
190
+ 'validateAuth',
191
+ 'validateRateLimit',
192
+ 'validatePermission',
193
+ 'validateAccess'
194
+ ];
195
+
196
+ return {
197
+ FunctionDeclaration(node) {
198
+ const functionName = node.id?.name;
199
+ if (!functionName) return;
200
+
201
+ // Skip if function name matches exclude patterns (API/config validation, not user input)
202
+ const lowerName = functionName.toLowerCase();
203
+ if (excludePatterns.some(pattern => lowerName.includes(pattern.toLowerCase()))) {
204
+ return;
205
+ }
206
+
207
+ // Check if this looks like a util that pace-core provides
208
+ for (const [paceCoreUtil, patterns] of Object.entries(utilPatterns)) {
209
+ if (paceCoreUtils.includes(paceCoreUtil)) {
210
+ for (const pattern of patterns) {
211
+ // Only match if the pattern is a significant part of the function name
212
+ // Don't match generic "validate" - it's too broad
213
+ if (paceCoreUtil === 'validateUserInput' && pattern === 'validate') {
214
+ // Skip generic "validate" - too many false positives
215
+ continue;
216
+ }
217
+
218
+ if (functionName.toLowerCase().includes(pattern.toLowerCase())) {
219
+ context.report({
220
+ node: node.id,
221
+ messageId: 'preferPaceCoreUtil',
222
+ data: {
223
+ util: paceCoreUtil,
224
+ customUtil: functionName
225
+ }
226
+ });
227
+ return;
228
+ }
229
+ }
230
+ }
231
+ }
232
+ }
233
+ };
234
+ }
235
+ },
236
+
237
+ /**
238
+ * Detect component files with names matching pace-core components
239
+ */
240
+ 'no-local-component-duplication': {
241
+ meta: {
242
+ type: 'problem',
243
+ docs: {
244
+ description: 'Disallow local components with names matching pace-core components',
245
+ category: 'Best Practices',
246
+ recommended: true
247
+ },
248
+ messages: {
249
+ duplicateComponent: "Component '{{componentName}}' conflicts with pace-core component. Use '@jmruthers/pace-core' instead of creating a local version."
250
+ }
251
+ },
252
+ create(context) {
253
+ const filename = context.getFilename();
254
+
255
+ // Exclude pace-core source files - these rules are for consuming apps
256
+ if (isPaceCoreSourceFile(filename)) {
257
+ return {};
258
+ }
259
+
260
+ const paceCoreComponents = getPaceCoreComponents();
261
+
262
+ // Only check component files (components/, src/components/, etc.)
263
+ if (!filename.match(/(components|Components)\//)) {
264
+ return {};
265
+ }
266
+
267
+ // Extract component name from filename
268
+ const basename = path.basename(filename, path.extname(filename));
269
+ const componentName = basename.replace(/\.(test|spec)$/, '');
270
+
271
+ return {
272
+ Program(node) {
273
+ // Check if this file exports a component with a name matching pace-core
274
+ if (paceCoreComponents.includes(componentName)) {
275
+ // Check if file exports this component
276
+ const hasExport = node.body.some(stmt => {
277
+ if (stmt.type === 'ExportNamedDeclaration') {
278
+ return stmt.declaration?.id?.name === componentName ||
279
+ stmt.specifiers?.some(spec => spec.exported.name === componentName);
280
+ }
281
+ if (stmt.type === 'ExportDefaultDeclaration') {
282
+ return stmt.declaration?.id?.name === componentName ||
283
+ stmt.declaration?.name === componentName;
284
+ }
285
+ return false;
286
+ });
287
+
288
+ if (hasExport) {
289
+ context.report({
290
+ node,
291
+ messageId: 'duplicateComponent',
292
+ data: {
293
+ componentName
294
+ }
295
+ });
296
+ }
297
+ }
298
+ }
299
+ };
300
+ }
301
+ },
302
+
303
+ /**
304
+ * Disallow inline styles
305
+ */
306
+ 'no-inline-styles': {
307
+ meta: {
308
+ type: 'problem',
309
+ docs: {
310
+ description: 'Disallow inline styles. Use pace-core components or Tailwind classes instead.',
311
+ category: 'Best Practices',
312
+ recommended: true
313
+ },
314
+ messages: {
315
+ inlineStyle: 'Inline style detected. Use pace-core components or Tailwind classes instead.'
316
+ },
317
+ hasSuggestions: true
318
+ },
319
+ create(context) {
320
+ const filename = context.getFilename();
321
+
322
+ // Exclude pace-core source files - these rules are for consuming apps
323
+ if (isPaceCoreSourceFile(filename)) {
324
+ return {};
325
+ }
326
+
327
+ return {
328
+ JSXAttribute(node) {
329
+ if (node.name && node.name.name === 'style') {
330
+ context.report({
331
+ node,
332
+ messageId: 'inlineStyle',
333
+ suggest: [{
334
+ desc: 'Remove inline style and use pace-core component styling or Tailwind utility classes',
335
+ fix(fixer) {
336
+ // Remove the style attribute
337
+ return fixer.remove(node);
338
+ }
339
+ }]
340
+ });
341
+ }
342
+ }
343
+ };
344
+ }
345
+ }
346
+ }
347
+ };
348
+
@@ -0,0 +1,113 @@
1
+ /**
2
+ * Component usage rules
3
+ * @package @jmruthers/pace-core
4
+ * @module ESLintRules/rules/components
5
+ */
6
+
7
+ const { isPaceCoreSourceFile } = require('../utils/helpers.cjs');
8
+
9
+ module.exports = {
10
+ rules: {
11
+ /**
12
+ * Prefer pace-core Form component over plain form tags and direct react-hook-form usage
13
+ */
14
+ 'prefer-pace-core-form': {
15
+ meta: {
16
+ type: 'problem',
17
+ docs: {
18
+ description: 'Disallow plain <form> tags and direct react-hook-form imports. Use pace-core Form component instead.',
19
+ category: 'Best Practices',
20
+ recommended: true
21
+ },
22
+ messages: {
23
+ plainFormTag: "Plain <form> tag detected. Use pace-core Form component instead.",
24
+ reactHookFormImport: "Direct import from 'react-hook-form' detected: {{imports}}. Use pace-core Form component instead. useFormContext is allowed when Form is imported from pace-core."
25
+ },
26
+ hasSuggestions: true
27
+ },
28
+ create(context) {
29
+ const filename = context.getFilename();
30
+
31
+ // Exclude pace-core source files - these rules are for consuming apps
32
+ if (isPaceCoreSourceFile(filename)) {
33
+ return {};
34
+ }
35
+
36
+ let hasPaceCoreForm = false;
37
+ const problematicImports = ['useForm', 'FormProvider', 'Controller', 'useWatch', 'useFieldArray', 'useController'];
38
+
39
+ return {
40
+ ImportDeclaration(node) {
41
+ const importSource = node.source.value;
42
+
43
+ // Check if Form is imported from pace-core
44
+ if (importSource === '@jmruthers/pace-core' ||
45
+ importSource === '@jmruthers/pace-core/components') {
46
+ const hasForm = node.specifiers.some(spec => {
47
+ if (spec.type === 'ImportSpecifier') {
48
+ return spec.imported.name === 'Form';
49
+ }
50
+ return false;
51
+ });
52
+ if (hasForm) {
53
+ hasPaceCoreForm = true;
54
+ }
55
+ }
56
+
57
+ // Check for react-hook-form imports
58
+ if (importSource === 'react-hook-form') {
59
+ const importedItems = node.specifiers
60
+ .filter(spec => spec.type === 'ImportSpecifier')
61
+ .map(spec => spec.imported.name);
62
+
63
+ const foundProblematic = importedItems.filter(item => problematicImports.includes(item));
64
+
65
+ // Allow useFormContext when Form is imported from pace-core
66
+ const isAcceptable = hasPaceCoreForm &&
67
+ foundProblematic.length === 1 &&
68
+ foundProblematic[0] === 'useFormContext';
69
+
70
+ if (foundProblematic.length > 0 && !isAcceptable) {
71
+ context.report({
72
+ node: node.source,
73
+ messageId: 'reactHookFormImport',
74
+ data: {
75
+ imports: foundProblematic.join(', ')
76
+ },
77
+ suggest: [{
78
+ desc: 'Use pace-core Form component instead',
79
+ fix(fixer) {
80
+ return fixer.remove(node);
81
+ }
82
+ }]
83
+ });
84
+ }
85
+ }
86
+ },
87
+
88
+ JSXOpeningElement(node) {
89
+ // Check for plain <form> tags (lowercase, not Form component)
90
+ if (node.name.type === 'JSXIdentifier') {
91
+ const elementName = node.name.name;
92
+ // Check if it's lowercase 'form' (not 'Form' component)
93
+ if (elementName === 'form') {
94
+ context.report({
95
+ node,
96
+ messageId: 'plainFormTag',
97
+ suggest: [{
98
+ desc: 'Replace with pace-core Form component',
99
+ fix(fixer) {
100
+ // This is complex to auto-fix, so we'll just report
101
+ return null;
102
+ }
103
+ }]
104
+ });
105
+ }
106
+ }
107
+ }
108
+ };
109
+ }
110
+ }
111
+ }
112
+ };
113
+
@@ -0,0 +1,102 @@
1
+ /**
2
+ * Import restriction rules
3
+ * @package @jmruthers/pace-core
4
+ * @module ESLintRules/rules/imports
5
+ */
6
+
7
+ const { getRestrictedImports } = require('../utils/manifest-loader.cjs');
8
+ const { getPaceCoreAlternative, isPaceCoreSourceFile } = require('../utils/helpers.cjs');
9
+
10
+ module.exports = {
11
+ rules: {
12
+ /**
13
+ * Block direct imports of libraries wrapped by pace-core
14
+ */
15
+ 'no-restricted-imports': {
16
+ meta: {
17
+ type: 'problem',
18
+ docs: {
19
+ description: 'Disallow direct imports of libraries that pace-core wraps',
20
+ category: 'Best Practices',
21
+ recommended: true
22
+ },
23
+ fixable: 'code',
24
+ hasSuggestions: true,
25
+ messages: {
26
+ restrictedImport: '{{message}} Import from {{alternative}} instead.',
27
+ restrictedImportWithReason: '{{message}} {{reason}}'
28
+ }
29
+ },
30
+ create(context) {
31
+ const filename = context.getFilename();
32
+
33
+ // Exclude pace-core source files - these rules are for consuming apps
34
+ if (isPaceCoreSourceFile(filename)) {
35
+ return {};
36
+ }
37
+
38
+ const restrictedImports = getRestrictedImports();
39
+ const restrictedModules = restrictedImports.map(imp => imp.module);
40
+
41
+ // Also catch @radix-ui/* patterns
42
+ const radixPattern = /^@radix-ui\//;
43
+
44
+ return {
45
+ ImportDeclaration(node) {
46
+ const importSource = node.source.value;
47
+
48
+ // Check exact matches
49
+ const restricted = restrictedImports.find(imp => imp.module === importSource);
50
+ if (restricted) {
51
+ context.report({
52
+ node: node.source,
53
+ messageId: 'restrictedImportWithReason',
54
+ data: {
55
+ message: `Direct import of '${importSource}' is not allowed.`,
56
+ reason: restricted.reason
57
+ },
58
+ suggest: [{
59
+ desc: `Use pace-core alternative: ${restricted.reason}`,
60
+ fix(fixer) {
61
+ // Suggest importing from pace-core instead
62
+ const paceCoreAlternative = getPaceCoreAlternative(importSource);
63
+ if (paceCoreAlternative) {
64
+ return fixer.replaceText(
65
+ node.source,
66
+ `'@jmruthers/pace-core${paceCoreAlternative}'`
67
+ );
68
+ }
69
+ return null;
70
+ }
71
+ }]
72
+ });
73
+ return;
74
+ }
75
+
76
+ // Check @radix-ui/* pattern
77
+ if (radixPattern.test(importSource) && !restrictedModules.includes(importSource)) {
78
+ context.report({
79
+ node: node.source,
80
+ messageId: 'restrictedImport',
81
+ data: {
82
+ message: `Direct import of '${importSource}' is not allowed.`,
83
+ alternative: '@jmruthers/pace-core'
84
+ },
85
+ suggest: [{
86
+ desc: 'Use pace-core component instead',
87
+ fix(fixer) {
88
+ return fixer.replaceText(
89
+ node.source,
90
+ "'@jmruthers/pace-core'"
91
+ );
92
+ }
93
+ }]
94
+ });
95
+ }
96
+ }
97
+ };
98
+ }
99
+ }
100
+ }
101
+ };
102
+