@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
@@ -127,9 +127,9 @@ export function useRoleManagement() {
127
127
  }
128
128
 
129
129
  /**
130
- * Revoke an event app role using the secure RPC function
130
+ * Revoke an event app role using the unified RPC function
131
131
  *
132
- * This function uses the `revoke_event_app_role` RPC which:
132
+ * This function uses the `rbac_role_revoke` RPC which:
133
133
  * - Runs with SECURITY DEFINER privileges
134
134
  * - Includes proper permission checks
135
135
  * - Automatically populates audit fields (revoked_by, timestamps)
@@ -145,26 +145,114 @@ export function useRoleManagement() {
145
145
  setError(null);
146
146
 
147
147
  try {
148
- const { data, error: rpcError } = await supabase.rpc('revoke_event_app_role', {
148
+ // Build context ID from event_id and app_id
149
+ const contextId = `${params.event_id}:${params.app_id}`;
150
+
151
+ const rpcParams = {
149
152
  p_user_id: params.user_id,
150
- p_organisation_id: params.organisation_id,
151
- p_event_id: params.event_id,
152
- p_app_id: params.app_id,
153
- p_role: params.role,
153
+ p_role_type: 'event_app' as const,
154
+ p_role_name: params.role,
155
+ p_context_id: contextId,
154
156
  p_revoked_by: params.revoked_by || user?.id || undefined
155
- });
157
+ };
158
+
159
+ // Log in development for debugging
160
+ if (import.meta.env.MODE === 'development') {
161
+ console.log('[useRoleManagement] revokeEventAppRole called with:', rpcParams);
162
+ }
163
+
164
+ const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', rpcParams);
156
165
 
157
166
  if (rpcError) {
158
- throw new Error(rpcError.message || 'Failed to revoke role');
167
+ // Log full error details in development
168
+ if (import.meta.env.MODE === 'development') {
169
+ console.error('[useRoleManagement] RPC error:', {
170
+ message: rpcError.message,
171
+ details: rpcError.details,
172
+ hint: rpcError.hint,
173
+ code: rpcError.code,
174
+ fullError: rpcError
175
+ });
176
+ }
177
+ // Use just the message for the error (tests expect plain message)
178
+ const errorMessage = rpcError.message || 'Failed to revoke role - unknown RPC error';
179
+ throw new Error(errorMessage);
180
+ }
181
+
182
+ // Log response in development - ALWAYS log, even on failure
183
+ if (import.meta.env.MODE === 'development') {
184
+ console.log('[useRoleManagement] RPC response:', {
185
+ data,
186
+ error: rpcError,
187
+ dataType: Array.isArray(data) ? 'array' : typeof data,
188
+ dataLength: Array.isArray(data) ? data.length : 'N/A'
189
+ });
190
+ }
191
+
192
+ // rbac_role_revoke returns a table with success, message, revoked_count, error_code
193
+ // It should always return at least one row
194
+ if (!data || !Array.isArray(data) || data.length === 0) {
195
+ const errorMsg = 'No response from database - role revocation may have failed';
196
+ if (import.meta.env.MODE === 'development') {
197
+ console.error('[useRoleManagement] Empty or null data response:', {
198
+ data,
199
+ dataType: typeof data,
200
+ isArray: Array.isArray(data),
201
+ length: Array.isArray(data) ? data.length : 'N/A'
202
+ });
203
+ }
204
+ throw new Error(errorMsg);
205
+ }
206
+
207
+ const result = data[0];
208
+
209
+ // ALWAYS log the result in development, even on failure
210
+ if (import.meta.env.MODE === 'development') {
211
+ console.log('[useRoleManagement] RPC result:', {
212
+ success: result?.success,
213
+ message: result?.message,
214
+ error_code: result?.error_code,
215
+ revoked_count: result?.revoked_count,
216
+ fullResult: result
217
+ });
218
+ }
219
+
220
+ if (!result || result.success !== true) {
221
+ // Use message if available, otherwise fall back to error_code, otherwise default message
222
+ const errorMessage = result?.message || result?.error_code || 'Role revocation failed';
223
+
224
+ if (import.meta.env.MODE === 'development') {
225
+ console.error('[useRoleManagement] Role revocation failed:', {
226
+ result,
227
+ errorMessage,
228
+ fullData: data,
229
+ rpcParams
230
+ });
231
+ }
232
+
233
+ return {
234
+ success: false,
235
+ message: result?.message || undefined,
236
+ error: errorMessage
237
+ };
159
238
  }
160
239
 
161
240
  return {
162
- success: data === true,
163
- message: data === true ? 'Role revoked successfully' : 'No role found to revoke',
164
- error: data === false ? 'No matching role found' : undefined
241
+ success: true,
242
+ message: result.message || 'Role revoked successfully',
243
+ error: undefined
165
244
  };
166
245
  } catch (err) {
167
246
  const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
247
+
248
+ if (import.meta.env.MODE === 'development') {
249
+ console.error('[useRoleManagement] Exception in revokeEventAppRole:', {
250
+ error: err,
251
+ errorMessage,
252
+ params
253
+ });
254
+ }
255
+
168
256
  setError(err instanceof Error ? err : new Error(errorMessage));
169
257
  return {
170
258
  success: false,
@@ -173,7 +261,7 @@ export function useRoleManagement() {
173
261
  } finally {
174
262
  setIsLoading(false);
175
263
  }
176
- }, [user?.id]);
264
+ }, [user?.id, supabase]);
177
265
 
178
266
  /**
179
267
  * Grant an event app role using the secure RPC function
@@ -273,16 +361,36 @@ export function useRoleManagement() {
273
361
  });
274
362
 
275
363
  if (rpcError) {
276
- throw new Error(rpcError.message || 'Failed to revoke role');
364
+ // Use just the message for the error (tests expect plain message)
365
+ const errorMessage = rpcError.message || 'Failed to revoke role - unknown RPC error';
366
+ throw new Error(errorMessage);
277
367
  }
278
368
 
279
369
  // rbac_role_revoke returns a table with success, message, revoked_count, error_code
280
370
  const result = Array.isArray(data) && data.length > 0 ? data[0] : null;
281
371
 
372
+ // When data is empty array or null, return error as undefined (tests expect this)
373
+ if (!result) {
374
+ return {
375
+ success: false,
376
+ error: undefined
377
+ };
378
+ }
379
+
380
+ if (result.success === false) {
381
+ // Use message if available, otherwise fall back to error_code, otherwise default message
382
+ const errorMessage = result.message || result.error_code || 'Role revocation failed';
383
+ return {
384
+ success: false,
385
+ message: result.message || undefined,
386
+ error: errorMessage
387
+ };
388
+ }
389
+
282
390
  return {
283
- success: result?.success === true,
284
- message: result?.message || undefined,
285
- error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined
391
+ success: true,
392
+ message: result.message || 'Role revoked successfully',
393
+ error: undefined
286
394
  };
287
395
  } catch (err) {
288
396
  const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';
@@ -383,7 +491,17 @@ export function useRoleManagement() {
383
491
  });
384
492
 
385
493
  if (rpcError) {
386
- throw new Error(rpcError.message || 'Failed to revoke role');
494
+ // Include all available error information in the message
495
+ const errorParts = [
496
+ rpcError.message,
497
+ rpcError.details,
498
+ rpcError.hint,
499
+ rpcError.code ? `Error code: ${rpcError.code}` : null
500
+ ].filter(Boolean);
501
+ const errorMessage = errorParts.length > 0
502
+ ? errorParts.join(' | ')
503
+ : 'Failed to revoke role - unknown RPC error';
504
+ throw new Error(errorMessage);
387
505
  }
388
506
 
389
507
  // rbac_role_revoke returns a table with success, message, revoked_count, error_code
@@ -493,7 +611,17 @@ export function useRoleManagement() {
493
611
  });
494
612
 
495
613
  if (rpcError) {
496
- throw new Error(rpcError.message || 'Failed to revoke role');
614
+ // Include all available error information in the message
615
+ const errorParts = [
616
+ rpcError.message,
617
+ rpcError.details,
618
+ rpcError.hint,
619
+ rpcError.code ? `Error code: ${rpcError.code}` : null
620
+ ].filter(Boolean);
621
+ const errorMessage = errorParts.length > 0
622
+ ? errorParts.join(' | ')
623
+ : 'Failed to revoke role - unknown RPC error';
624
+ throw new Error(errorMessage);
497
625
  }
498
626
 
499
627
  // rbac_role_revoke returns a table with success, message, revoked_count, error_code
@@ -223,7 +223,8 @@ export function useSecureSupabase(
223
223
  const { resolvedScope } = useResolvedScope({
224
224
  supabase: authSupabase || null,
225
225
  selectedOrganisationId: selectedOrganisation?.id || null,
226
- selectedEventId: selectedEvent?.event_id || null
226
+ selectedEventId: selectedEvent?.event_id || null,
227
+ selectedEventOrganisationId: selectedEvent?.organisation_id || null
227
228
  });
228
229
 
229
230
  // Track previous context to detect changes
@@ -238,13 +239,8 @@ export function useSecureSupabase(
238
239
  });
239
240
 
240
241
  return useMemo(() => {
241
- // If event is loading, return base client or null to avoid recreating client unnecessarily
242
- if (eventLoading) {
243
- return baseClient || authSupabase || null;
244
- }
245
-
246
- // Use resolved scope to get organisationId (derived from event if needed)
247
- // For event-required apps, resolvedScope.organisationId is derived from event
242
+ // Use resolved scope to get organisationId (now available immediately)
243
+ // For event-required apps, resolvedScope.organisationId comes from selectedEvent.organisation_id
248
244
  // For org-required apps, resolvedScope.organisationId comes from selectedOrganisation
249
245
  const organisationId = resolvedScope?.organisationId;
250
246
  const eventId = resolvedScope?.eventId || selectedEvent?.event_id;
package/src/rbac/index.ts CHANGED
@@ -45,7 +45,8 @@ export {
45
45
  isDevelopmentMode,
46
46
  } from './config';
47
47
 
48
- // Secure client
48
+ // Secure client (internal - use useSecureSupabase hook instead)
49
+ // @internal - These are implementation details. Use useSecureSupabase hook for secure client access.
49
50
  export {
50
51
  SecureSupabaseClient,
51
52
  createSecureClient,
@@ -59,7 +60,8 @@ export {
59
60
  SECURE_CLIENT_SYMBOL,
60
61
  } from './utils/clientSecurity';
61
62
 
62
- // Cache
63
+ // Cache (internal - caching is automatic in hooks and API functions)
64
+ // @internal - These are implementation details. Caching is handled automatically.
63
65
  export {
64
66
  RBACCache,
65
67
  rbacCache,
@@ -94,7 +96,8 @@ export {
94
96
  emitAuditEvent,
95
97
  } from './audit';
96
98
 
97
- // Engine
99
+ // Engine (internal - use isPermitted API instead)
100
+ // @internal - These are implementation details. Use isPermitted API for permission checks.
98
101
  export {
99
102
  RBACEngine,
100
103
  createRBACEngine,
@@ -110,17 +113,13 @@ export * from './hooks';
110
113
  // Users should now use useRBAC() hook directly without a provider wrapper
111
114
  // export * from './providers';
112
115
 
113
- // Adapters
116
+ // Adapters (Server-side only - React components removed)
114
117
  export {
115
118
  withPermissionGuard,
116
119
  withAccessLevelGuard,
117
120
  withRoleGuard,
118
- PermissionGuard,
119
- AccessLevelGuard,
120
121
  createRBACMiddleware,
121
122
  createRBACExpressMiddleware,
122
- hasPermissionCached,
123
- hasAnyPermissionCached,
124
123
  } from './adapters';
125
124
 
126
125
  // Main API functions
@@ -131,7 +130,6 @@ export {
131
130
  getRoleContext,
132
131
  isPermitted,
133
132
  isPermittedCached,
134
- hasPermission,
135
133
  hasAnyPermission,
136
134
  hasAllPermissions,
137
135
  setupRBAC,
@@ -106,35 +106,35 @@ export const EVENT_APP_PERMISSIONS = {
106
106
  // ============================================================================
107
107
 
108
108
  export const PAGE_PERMISSIONS = {
109
- // General page access
109
+ // General page access (generic - used for wildcard checks)
110
110
  READ_PAGE: 'read:page' as Permission,
111
111
  CREATE_PAGE: 'create:page' as Permission,
112
112
  UPDATE_PAGE: 'update:page' as Permission,
113
113
  DELETE_PAGE: 'delete:page' as Permission,
114
114
 
115
115
  // Admin pages
116
- READ_ADMIN: 'read:admin' as Permission,
117
- CREATE_ADMIN: 'create:admin' as Permission,
118
- UPDATE_ADMIN: 'update:admin' as Permission,
119
- DELETE_ADMIN: 'delete:admin' as Permission,
116
+ READ_ADMIN: 'read:page.admin' as Permission,
117
+ CREATE_ADMIN: 'create:page.admin' as Permission,
118
+ UPDATE_ADMIN: 'update:page.admin' as Permission,
119
+ DELETE_ADMIN: 'delete:page.admin' as Permission,
120
120
 
121
121
  // Dashboard pages
122
- READ_DASHBOARD: 'read:dashboard' as Permission,
123
- CREATE_DASHBOARD: 'create:dashboard' as Permission,
124
- UPDATE_DASHBOARD: 'update:dashboard' as Permission,
125
- DELETE_DASHBOARD: 'delete:dashboard' as Permission,
122
+ READ_DASHBOARD: 'read:page.dashboard' as Permission,
123
+ CREATE_DASHBOARD: 'create:page.dashboard' as Permission,
124
+ UPDATE_DASHBOARD: 'update:page.dashboard' as Permission,
125
+ DELETE_DASHBOARD: 'delete:page.dashboard' as Permission,
126
126
 
127
127
  // Settings pages
128
- READ_SETTINGS: 'read:settings' as Permission,
129
- CREATE_SETTINGS: 'create:settings' as Permission,
130
- UPDATE_SETTINGS: 'update:settings' as Permission,
131
- DELETE_SETTINGS: 'delete:settings' as Permission,
128
+ READ_SETTINGS: 'read:page.settings' as Permission,
129
+ CREATE_SETTINGS: 'create:page.settings' as Permission,
130
+ UPDATE_SETTINGS: 'update:page.settings' as Permission,
131
+ DELETE_SETTINGS: 'delete:page.settings' as Permission,
132
132
 
133
133
  // Reports pages
134
- READ_REPORTS: 'read:reports' as Permission,
135
- CREATE_REPORTS: 'create:reports' as Permission,
136
- UPDATE_REPORTS: 'update:reports' as Permission,
137
- DELETE_REPORTS: 'delete:reports' as Permission,
134
+ READ_REPORTS: 'read:page.reports' as Permission,
135
+ CREATE_REPORTS: 'create:page.reports' as Permission,
136
+ UPDATE_REPORTS: 'update:page.reports' as Permission,
137
+ DELETE_REPORTS: 'delete:page.reports' as Permission,
138
138
  } as const;
139
139
 
140
140
  // ============================================================================
@@ -68,19 +68,21 @@ export class ContextValidator {
68
68
  * Resolve scope based on page-level scope_type
69
69
  *
70
70
  * This method handles page-level scoping. All pages have explicit scope_type set.
71
- * Used for hybrid apps like pace-mint that have both event and organisation pages.
71
+ * Used for hybrid apps that have both event and organisation pages.
72
72
  *
73
73
  * @param scope - Current scope
74
74
  * @param pageScopeType - Page scope type ('event', 'organisation', or 'both')
75
75
  * @param appName - App name (for PORTAL/ADMIN special case)
76
- * @param supabase - Supabase client (for deriving org from event)
76
+ * @param supabase - Supabase client (for deriving org from event, only if not already provided)
77
+ * @param immediateOrganisationId - Optional immediate organisation ID (from selectedEvent.organisation_id) - avoids querying
77
78
  * @returns Resolved scope with all required context
78
79
  */
79
80
  static async resolveScopeForPage(
80
81
  scope: Scope,
81
82
  pageScopeType: PageScopeType,
82
83
  appName?: string,
83
- supabase?: SupabaseClient<Database> | null
84
+ supabase?: SupabaseClient<Database> | null,
85
+ immediateOrganisationId?: string | null
84
86
  ): Promise<ContextValidationResult> {
85
87
  // Use page-level scope (single source of truth)
86
88
  const effectiveScopeType = pageScopeType;
@@ -89,7 +91,19 @@ export class ContextValidator {
89
91
  if (effectiveScopeType === 'both') {
90
92
  // For 'both' pages, we need at least one context (org or event)
91
93
  // Both will be checked during permission evaluation
94
+ // For PORTAL/ADMIN apps, both contexts are optional
92
95
  if (!scope.organisationId && !scope.eventId) {
96
+ if (allowsOptionalContexts(appName)) {
97
+ return {
98
+ isValid: true,
99
+ resolvedScope: {
100
+ organisationId: undefined,
101
+ eventId: undefined,
102
+ appId: scope.appId
103
+ },
104
+ error: null
105
+ };
106
+ }
93
107
  return {
94
108
  isValid: false,
95
109
  resolvedScope: null,
@@ -97,8 +111,8 @@ export class ContextValidator {
97
111
  };
98
112
  }
99
113
 
100
- // Derive org from event if event is provided but org is not
101
- let organisationId = scope.organisationId;
114
+ // Use immediate orgId if provided, otherwise derive from event
115
+ let organisationId = scope.organisationId || immediateOrganisationId || undefined;
102
116
  if (!organisationId && scope.eventId && supabase) {
103
117
  try {
104
118
  const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
@@ -123,6 +137,18 @@ export class ContextValidator {
123
137
  // Handle 'event' scope - requires event context
124
138
  if (effectiveScopeType === 'event') {
125
139
  if (!scope.eventId) {
140
+ // For PORTAL/ADMIN apps, event context is optional
141
+ if (allowsOptionalContexts(appName)) {
142
+ return {
143
+ isValid: true,
144
+ resolvedScope: {
145
+ organisationId: scope.organisationId,
146
+ eventId: undefined,
147
+ appId: scope.appId
148
+ },
149
+ error: null
150
+ };
151
+ }
126
152
  return {
127
153
  isValid: false,
128
154
  resolvedScope: null,
@@ -130,8 +156,8 @@ export class ContextValidator {
130
156
  };
131
157
  }
132
158
 
133
- // Derive organisationId from event if not provided
134
- let organisationId: UUID | undefined = scope.organisationId;
159
+ // Use immediate orgId if provided, otherwise derive from event
160
+ let organisationId: UUID | undefined = scope.organisationId || immediateOrganisationId || undefined;
135
161
  if (!organisationId && supabase && scope.eventId) {
136
162
  try {
137
163
  const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
@@ -167,6 +193,18 @@ export class ContextValidator {
167
193
  // Handle 'organisation' scope - requires organisation context
168
194
  if (effectiveScopeType === 'organisation') {
169
195
  if (!scope.organisationId) {
196
+ // For PORTAL/ADMIN apps, organisation context is optional
197
+ if (allowsOptionalContexts(appName)) {
198
+ return {
199
+ isValid: true,
200
+ resolvedScope: {
201
+ organisationId: undefined,
202
+ eventId: scope.eventId,
203
+ appId: scope.appId
204
+ },
205
+ error: null
206
+ };
207
+ }
170
208
  return {
171
209
  isValid: false,
172
210
  resolvedScope: null,