@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,994 @@
1
+ import { AccessDenied } from './chunk-4T7OBVTU.js';
2
+ import { useResolvedScope, scopeEqual, useCan, useMultiplePermissions } from './chunk-7TYHROIV.js';
3
+ import { useUnifiedAuth } from './chunk-FTCRZOG2.js';
4
+ import { getRBACLogger, getRBACConfig, RBACNotInitializedError } from './chunk-ZFYPMX46.js';
5
+ import { createLogger } from './chunk-TTRFSOKR.js';
6
+ import React, { useRef, useMemo, useState, useEffect } from 'react';
7
+ import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
8
+
9
+ // src/rbac/types/functions.ts
10
+ var RPCFunction = /* @__PURE__ */ ((RPCFunction2) => {
11
+ RPCFunction2["RBAC_PERMISSION_CHECK"] = "rbac_permission_check";
12
+ RPCFunction2["RBAC_PERMISSIONS_GET"] = "rbac_permissions_get";
13
+ RPCFunction2["RBAC_ACCESS_VALIDATE"] = "rbac_access_validate";
14
+ RPCFunction2["RBAC_PAGE_ACCESS_CHECK"] = "rbac_page_access_check";
15
+ RPCFunction2["RBAC_ROLE_GRANT"] = "rbac_role_grant";
16
+ RPCFunction2["RBAC_ROLE_REVOKE"] = "rbac_role_revoke";
17
+ RPCFunction2["RBAC_ROLES_LIST"] = "rbac_roles_list";
18
+ RPCFunction2["RBAC_ROLE_VALIDATE"] = "rbac_role_validate";
19
+ RPCFunction2["RBAC_SESSION_TRACK"] = "rbac_session_track";
20
+ RPCFunction2["RBAC_AUDIT_LOG"] = "rbac_audit_log";
21
+ return RPCFunction2;
22
+ })(RPCFunction || {});
23
+ var RBACErrorCode = /* @__PURE__ */ ((RBACErrorCode2) => {
24
+ RBACErrorCode2["USER_NOT_FOUND"] = "USER_NOT_FOUND";
25
+ RBACErrorCode2["INVALID_ROLE_TYPE"] = "INVALID_ROLE_TYPE";
26
+ RBACErrorCode2["INVALID_ROLE_NAME"] = "INVALID_ROLE_NAME";
27
+ RBACErrorCode2["MISSING_ORGANISATION_ID"] = "MISSING_ORGANISATION_ID";
28
+ RBACErrorCode2["MISSING_EVENT_APP_CONTEXT"] = "MISSING_EVENT_APP_CONTEXT";
29
+ RBACErrorCode2["ORGANISATION_NOT_FOUND"] = "ORGANISATION_NOT_FOUND";
30
+ RBACErrorCode2["EVENT_NOT_FOUND"] = "EVENT_NOT_FOUND";
31
+ RBACErrorCode2["APP_NOT_FOUND"] = "APP_NOT_FOUND";
32
+ RBACErrorCode2["INVALID_SESSION_TYPE"] = "INVALID_SESSION_TYPE";
33
+ RBACErrorCode2["INVALID_EVENT_TYPE"] = "INVALID_EVENT_TYPE";
34
+ RBACErrorCode2["DATABASE_ERROR"] = "DATABASE_ERROR";
35
+ RBACErrorCode2["ROLE_NOT_FOUND"] = "ROLE_NOT_FOUND";
36
+ RBACErrorCode2["USER_NOT_AUTHENTICATED"] = "USER_NOT_AUTHENTICATED";
37
+ RBACErrorCode2["INVALID_GLOBAL_ROLE"] = "INVALID_GLOBAL_ROLE";
38
+ RBACErrorCode2["INVALID_ORGANISATION_ROLE"] = "INVALID_ORGANISATION_ROLE";
39
+ RBACErrorCode2["INVALID_EVENT_APP_ROLE"] = "INVALID_EVENT_APP_ROLE";
40
+ RBACErrorCode2["INVALID_EVENT_APP_FORMAT"] = "INVALID_EVENT_APP_FORMAT";
41
+ RBACErrorCode2["MISSING_CONTEXT"] = "MISSING_CONTEXT";
42
+ RBACErrorCode2["INVALID_CONTEXT"] = "INVALID_CONTEXT";
43
+ RBACErrorCode2["GRANTED_BY_NOT_FOUND"] = "GRANTED_BY_NOT_FOUND";
44
+ return RBACErrorCode2;
45
+ })(RBACErrorCode || {});
46
+ var PagePermissionGuardComponent = ({
47
+ pageName,
48
+ operation,
49
+ children,
50
+ fallback = /* @__PURE__ */ jsx(AccessDenied, {}),
51
+ strictMode = true,
52
+ auditLog = true,
53
+ pageId,
54
+ scope,
55
+ onDenied,
56
+ loading = /* @__PURE__ */ jsx(DefaultLoading, {})
57
+ }) => {
58
+ const renderCountRef = useRef(0);
59
+ renderCountRef.current += 1;
60
+ useMemo(() => Math.random().toString(36).substr(2, 9), []);
61
+ const { user, selectedOrganisation, selectedEvent, supabase, appId: contextAppId, appName } = useUnifiedAuth();
62
+ const [hasChecked, setHasChecked] = useState(false);
63
+ const hasLoggedSuperAdminRef = useRef(false);
64
+ const effectivePageId = useMemo(() => {
65
+ return pageId || pageName;
66
+ }, [pageId, pageName]);
67
+ const [isSuperAdmin, setIsSuperAdmin] = useState(null);
68
+ useEffect(() => {
69
+ if (!user?.id) {
70
+ setIsSuperAdmin(false);
71
+ return;
72
+ }
73
+ let cancelled = false;
74
+ const checkSuperAdmin = async () => {
75
+ const startTime = Date.now();
76
+ try {
77
+ const { isSuperAdmin: checkSuperAdmin2 } = await import('./api-Y4MQWOFW.js');
78
+ const timeoutPromise = new Promise((_, reject) => {
79
+ setTimeout(() => reject(new Error("Super admin check timeout")), 1e4);
80
+ });
81
+ const isSuper = await Promise.race([
82
+ checkSuperAdmin2(user.id),
83
+ timeoutPromise
84
+ ]);
85
+ const elapsed = Date.now() - startTime;
86
+ if (!cancelled) {
87
+ setIsSuperAdmin(isSuper);
88
+ if (false) ;
89
+ }
90
+ } catch (err) {
91
+ const elapsed = Date.now() - startTime;
92
+ if (!cancelled) {
93
+ console.error("[PagePermissionGuard] Error checking super admin", {
94
+ error: err,
95
+ userId: user.id,
96
+ elapsedMs: elapsed
97
+ });
98
+ setIsSuperAdmin(false);
99
+ }
100
+ }
101
+ };
102
+ checkSuperAdmin();
103
+ return () => {
104
+ cancelled = true;
105
+ };
106
+ }, [user?.id]);
107
+ const { resolvedScope: hookResolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
108
+ supabase,
109
+ selectedOrganisationId: selectedOrganisation?.id || null,
110
+ selectedEventId: selectedEvent?.event_id || null,
111
+ selectedEventOrganisationId: selectedEvent?.organisation_id || null
112
+ });
113
+ const shouldBypassScopeForSuperAdmin = isSuperAdmin === true;
114
+ const allowsOptionalContexts = appName === "PORTAL" || appName === "ADMIN";
115
+ const effectiveScope = scope || (hookResolvedScope ? {
116
+ ...hookResolvedScope,
117
+ appId: hookResolvedScope.appId || (allowsOptionalContexts ? contextAppId : void 0)
118
+ } : allowsOptionalContexts && contextAppId ? {
119
+ organisationId: void 0,
120
+ eventId: void 0,
121
+ appId: contextAppId
122
+ } : selectedEvent?.event_id ? {
123
+ organisationId: void 0,
124
+ // Will be derived from event
125
+ eventId: selectedEvent.event_id,
126
+ appId: contextAppId || void 0
127
+ } : null);
128
+ const checkError = scopeError;
129
+ const permission = useMemo(() => {
130
+ return `${operation}:page.${pageName}`;
131
+ }, [operation, pageName]);
132
+ const prevScopeRef = useRef(null);
133
+ const stableScope = useMemo(() => {
134
+ if (allowsOptionalContexts && effectiveScope) {
135
+ const newScope2 = {
136
+ organisationId: effectiveScope.organisationId,
137
+ appId: effectiveScope.appId || contextAppId || void 0,
138
+ eventId: effectiveScope.eventId
139
+ };
140
+ if (scopeEqual(prevScopeRef.current, newScope2)) {
141
+ return prevScopeRef.current;
142
+ }
143
+ prevScopeRef.current = newScope2;
144
+ return newScope2;
145
+ }
146
+ const newScope = effectiveScope && effectiveScope.organisationId ? {
147
+ organisationId: effectiveScope.organisationId,
148
+ appId: effectiveScope.appId || contextAppId || void 0,
149
+ eventId: effectiveScope.eventId || void 0
150
+ } : {
151
+ organisationId: effectiveScope?.organisationId || void 0,
152
+ appId: effectiveScope?.appId || contextAppId || void 0,
153
+ eventId: effectiveScope?.eventId || selectedEvent?.event_id || void 0
154
+ };
155
+ if (scopeEqual(prevScopeRef.current, newScope)) {
156
+ return prevScopeRef.current;
157
+ }
158
+ prevScopeRef.current = newScope;
159
+ return newScope;
160
+ }, [effectiveScope, appName, contextAppId, selectedEvent?.event_id]);
161
+ const scopeForPermissionCheck = shouldBypassScopeForSuperAdmin && !stableScope?.organisationId ? {
162
+ organisationId: void 0,
163
+ appId: contextAppId || void 0,
164
+ eventId: selectedEvent?.event_id || void 0
165
+ } : stableScope;
166
+ const shouldSkipPermissionCheck = isSuperAdmin === true;
167
+ const { can, isLoading: canIsLoading, error: canError } = useCan(
168
+ user?.id || "",
169
+ shouldSkipPermissionCheck ? { organisationId: void 0, appId: contextAppId || void 0, eventId: void 0 } : scopeForPermissionCheck,
170
+ permission,
171
+ effectivePageId,
172
+ true,
173
+ // Use cache
174
+ isSuperAdmin,
175
+ // precomputedSuperAdmin - null if checking, true/false if checked
176
+ appName
177
+ // Pass appName for PORTAL/ADMIN special case
178
+ );
179
+ const effectiveCan = shouldSkipPermissionCheck ? true : can;
180
+ const effectiveIsLoading = shouldSkipPermissionCheck ? false : canIsLoading;
181
+ const isLoading = shouldBypassScopeForSuperAdmin ? effectiveIsLoading : scopeLoading || effectiveIsLoading;
182
+ const error = checkError || canError;
183
+ useEffect(() => {
184
+ if (!isLoading && !error) {
185
+ setHasChecked(true);
186
+ if (!effectiveCan && onDenied) {
187
+ onDenied(pageName, operation);
188
+ }
189
+ } else if (error) {
190
+ setHasChecked(true);
191
+ }
192
+ }, [effectiveCan, isLoading, error, pageName, operation, onDenied]);
193
+ useEffect(() => {
194
+ if (auditLog && hasChecked && !isLoading) {
195
+ const rbacLogger = getRBACLogger();
196
+ rbacLogger.debug("Page access attempt:", {
197
+ pageName,
198
+ operation,
199
+ userId: user?.id,
200
+ scope: effectiveScope,
201
+ allowed: effectiveCan,
202
+ isSuperAdmin,
203
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
204
+ });
205
+ }
206
+ }, [auditLog, hasChecked, isLoading, pageName, operation, user?.id, effectiveScope, effectiveCan, isSuperAdmin]);
207
+ useEffect(() => {
208
+ if (strictMode && hasChecked && !isLoading && !effectiveCan && !shouldBypassScopeForSuperAdmin) {
209
+ const logger = getRBACLogger();
210
+ logger.error(`STRICT MODE VIOLATION: User attempted to access protected page without permission`, {
211
+ pageName,
212
+ operation,
213
+ permission: `${operation}:page.${pageName}`,
214
+ pageId: effectivePageId,
215
+ userId: user?.id,
216
+ scope: effectiveScope,
217
+ scopeValid: allowsOptionalContexts ? true : effectiveScope !== null,
218
+ // PORTAL/ADMIN allow scope without org/event
219
+ checkError,
220
+ canError,
221
+ isSuperAdmin,
222
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
223
+ });
224
+ }
225
+ }, [strictMode, hasChecked, isLoading, effectiveCan, shouldBypassScopeForSuperAdmin, pageName, operation, effectivePageId, user?.id, effectiveScope, allowsOptionalContexts, checkError, canError, isSuperAdmin]);
226
+ const hasValidScopeForPagePermissions = shouldBypassScopeForSuperAdmin ? true : allowsOptionalContexts ? true : effectiveScope !== null;
227
+ const hasValidUser = user && user.id;
228
+ const isPermissionCheckComplete = hasChecked && !isLoading;
229
+ const shouldShowAccessDenied = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && !effectiveCan;
230
+ const shouldShowContent = isPermissionCheckComplete && hasValidScopeForPagePermissions && hasValidUser && !checkError && effectiveCan;
231
+ effectiveScope ? `${effectiveScope.organisationId}-${effectiveScope.eventId}-${effectiveScope.appId}` : "no-scope";
232
+ useRef("");
233
+ useEffect(() => {
234
+ }, [pageName, user?.id, isSuperAdmin, isLoading, scopeLoading, canIsLoading, hasChecked, hasValidUser, effectiveCan, stableScope, effectiveScope]);
235
+ useEffect(() => {
236
+ if (isLoading && isSuperAdmin === null && hasValidUser) {
237
+ const timeout = setTimeout(() => {
238
+ console.warn("[PagePermissionGuard] Permission check taking longer than expected", {
239
+ pageName,
240
+ userId: user?.id,
241
+ isSuperAdmin,
242
+ scopeLoading,
243
+ canIsLoading,
244
+ hasChecked,
245
+ stableScope,
246
+ effectiveScope,
247
+ appName
248
+ });
249
+ }, 5e3);
250
+ return () => clearTimeout(timeout);
251
+ }
252
+ }, [isLoading, isSuperAdmin, hasValidUser, pageName, user?.id, scopeLoading, canIsLoading, hasChecked, stableScope, effectiveScope, appName]);
253
+ useEffect(() => {
254
+ if (isSuperAdmin === true && hasValidUser && !hasLoggedSuperAdminRef.current && false) ;
255
+ if (isSuperAdmin !== true) {
256
+ hasLoggedSuperAdminRef.current = false;
257
+ }
258
+ }, [isSuperAdmin, hasValidUser, pageName, user?.id, operation]);
259
+ if (isSuperAdmin === true && hasValidUser) {
260
+ return /* @__PURE__ */ jsx(Fragment, { children });
261
+ }
262
+ if (isLoading || !hasValidUser || !hasChecked || isSuperAdmin === null) {
263
+ return loading || /* @__PURE__ */ jsx("div", { children: "Checking permissions..." });
264
+ }
265
+ if (checkError && !can) {
266
+ return fallback;
267
+ }
268
+ if (shouldShowAccessDenied) {
269
+ return fallback;
270
+ }
271
+ if (shouldShowContent) {
272
+ return /* @__PURE__ */ jsx(Fragment, { children });
273
+ }
274
+ return fallback;
275
+ };
276
+ function DefaultLoading() {
277
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center min-h-[200px] p-8", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
278
+ /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full size-8 border-b-2 border-main-600" }),
279
+ /* @__PURE__ */ jsx("span", { className: "text-sec-600", children: "Checking permissions..." })
280
+ ] }) });
281
+ }
282
+ var PagePermissionGuard = React.memo(PagePermissionGuardComponent);
283
+ function NavigationGuard({
284
+ navigationItem,
285
+ children,
286
+ fallback = /* @__PURE__ */ jsx(AccessDenied, {}),
287
+ strictMode = true,
288
+ auditLog = true,
289
+ scope,
290
+ onDenied,
291
+ loading = /* @__PURE__ */ jsx(DefaultLoading2, {}),
292
+ requireAll = true
293
+ }) {
294
+ const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
295
+ const [hasChecked, setHasChecked] = useState(false);
296
+ const { resolvedScope: hookResolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
297
+ supabase,
298
+ selectedOrganisationId: selectedOrganisation?.id || null,
299
+ selectedEventId: selectedEvent?.event_id || null,
300
+ selectedEventOrganisationId: selectedEvent?.organisation_id || null
301
+ });
302
+ const effectiveScope = scope || hookResolvedScope;
303
+ const checkError = scopeError;
304
+ const validPermissions = (navigationItem.permissions || []).filter(
305
+ (p) => typeof p === "string" && (p.startsWith("read:") || p.startsWith("create:") || p.startsWith("update:") || p.startsWith("delete:"))
306
+ );
307
+ const { results: permissionResults, isLoading: permissionsLoading, error: permissionsError } = useMultiplePermissions(
308
+ user?.id || "",
309
+ effectiveScope || { eventId: selectedEvent?.event_id || void 0 },
310
+ validPermissions,
311
+ true
312
+ // Use cache
313
+ );
314
+ const isLoading = scopeLoading || permissionsLoading;
315
+ const error = checkError || permissionsError;
316
+ const hasRequiredPermissions = useMemo(() => {
317
+ if (!navigationItem.permissions || navigationItem.permissions.length === 0) return true;
318
+ if (requireAll) {
319
+ return Object.values(permissionResults).every((result) => result === true);
320
+ } else {
321
+ return Object.values(permissionResults).some((result) => result === true);
322
+ }
323
+ }, [navigationItem.permissions, permissionResults, requireAll]);
324
+ useEffect(() => {
325
+ if (!isLoading && !error) {
326
+ setHasChecked(true);
327
+ if (!hasRequiredPermissions && onDenied) {
328
+ onDenied(navigationItem);
329
+ }
330
+ } else if (error) {
331
+ setHasChecked(true);
332
+ }
333
+ }, [hasRequiredPermissions, isLoading, error, navigationItem, onDenied]);
334
+ useEffect(() => {
335
+ }, [auditLog, hasChecked, isLoading, navigationItem, user?.id, effectiveScope, hasRequiredPermissions, requireAll]);
336
+ useEffect(() => {
337
+ if (strictMode && hasChecked && !isLoading && !hasRequiredPermissions) {
338
+ const logger = getRBACLogger();
339
+ logger.error(`STRICT MODE VIOLATION: User attempted to access protected navigation item without permission`, {
340
+ navigationItem: navigationItem.id,
341
+ permissions: navigationItem.permissions,
342
+ userId: user?.id,
343
+ scope: effectiveScope,
344
+ requireAll,
345
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
346
+ });
347
+ }
348
+ }, [strictMode, hasChecked, isLoading, hasRequiredPermissions, navigationItem, user?.id, effectiveScope, requireAll]);
349
+ if (isLoading || !effectiveScope || !hasChecked) {
350
+ return /* @__PURE__ */ jsx(Fragment, { children: loading });
351
+ }
352
+ if (checkError) {
353
+ const logger = getRBACLogger();
354
+ logger.error(`Permission check failed for navigation item ${navigationItem.id}:`, checkError);
355
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
356
+ }
357
+ if (!hasRequiredPermissions) {
358
+ return /* @__PURE__ */ jsx(Fragment, { children: fallback });
359
+ }
360
+ return /* @__PURE__ */ jsx(Fragment, { children });
361
+ }
362
+ function DefaultLoading2() {
363
+ return /* @__PURE__ */ jsx("div", { className: "flex items-center justify-center p-2", children: /* @__PURE__ */ jsxs("div", { className: "flex items-center space-x-2", children: [
364
+ /* @__PURE__ */ jsx("div", { className: "animate-spin rounded-full size-4 border-b-2 border-main-600" }),
365
+ /* @__PURE__ */ jsx("span", { className: "text-sm text-sec-600", children: "Checking..." })
366
+ ] }) });
367
+ }
368
+
369
+ // src/rbac/adapters.tsx
370
+ function withPermissionGuard(config, handler) {
371
+ return async (...args) => {
372
+ const [req] = args;
373
+ const userId = req.user?.id;
374
+ const organisationId = req.organisationId;
375
+ const eventId = req.eventId;
376
+ const appId = req.appId;
377
+ if (!userId || !organisationId) {
378
+ throw new Error("User context required for permission check");
379
+ }
380
+ const { isPermitted: isPermitted2 } = await import('./api-Y4MQWOFW.js');
381
+ const hasPermission = await isPermitted2({
382
+ userId,
383
+ scope: { organisationId, eventId, appId },
384
+ permission: config.permission,
385
+ pageId: config.pageId
386
+ });
387
+ if (!hasPermission) {
388
+ throw new Error(`Permission denied: ${config.permission}`);
389
+ }
390
+ return handler(...args);
391
+ };
392
+ }
393
+ function withAccessLevelGuard(minLevel, handler) {
394
+ return async (...args) => {
395
+ const [req] = args;
396
+ const userId = req.user?.id;
397
+ const organisationId = req.organisationId;
398
+ const eventId = req.eventId;
399
+ const appId = req.appId;
400
+ if (!userId || !organisationId) {
401
+ throw new Error("User context required for access level check");
402
+ }
403
+ const { getAccessLevel: getAccessLevel2 } = await import('./api-Y4MQWOFW.js');
404
+ const accessLevel = await getAccessLevel2({
405
+ userId,
406
+ scope: { organisationId, eventId, appId }
407
+ });
408
+ const levelHierarchy = ["viewer", "participant", "planner", "admin", "super"];
409
+ const userLevelIndex = levelHierarchy.indexOf(accessLevel);
410
+ const requiredLevelIndex = levelHierarchy.indexOf(minLevel);
411
+ if (userLevelIndex < requiredLevelIndex) {
412
+ throw new Error(`Access level required: ${minLevel}, got: ${accessLevel}`);
413
+ }
414
+ return handler(...args);
415
+ };
416
+ }
417
+ function withRoleGuard(config, handler) {
418
+ return async (...args) => {
419
+ const [req] = args;
420
+ const userId = req.user?.id;
421
+ const organisationId = req.organisationId;
422
+ const eventId = req.eventId;
423
+ const appId = req.appId;
424
+ if (!userId || !organisationId) {
425
+ throw new Error("User context required for role check");
426
+ }
427
+ if (config.globalRoles && config.globalRoles.length > 0) {
428
+ const { isSuperAdmin } = await import('./api-Y4MQWOFW.js');
429
+ const isSuper = await isSuperAdmin(userId);
430
+ if (isSuper) {
431
+ if (organisationId) {
432
+ const { emitAuditEvent: emitAuditEvent2 } = await import('./audit-MYQXYZFU.js');
433
+ await emitAuditEvent2({
434
+ type: "permission_check",
435
+ userId,
436
+ organisationId,
437
+ eventId,
438
+ appId,
439
+ permission: "bypass:all",
440
+ decision: true,
441
+ source: "api",
442
+ bypass: true,
443
+ duration_ms: 0,
444
+ metadata: {
445
+ operation: "role_guard",
446
+ reason: "super_admin_bypass"
447
+ }
448
+ });
449
+ }
450
+ return handler(...args);
451
+ }
452
+ }
453
+ if (config.organisationRoles && config.organisationRoles.length > 0) {
454
+ const { isOrganisationAdmin } = await import('./api-Y4MQWOFW.js');
455
+ const isOrgAdmin = await isOrganisationAdmin(userId, organisationId);
456
+ if (!isOrgAdmin && config.requireAll !== false) {
457
+ throw new Error(`Organisation admin role required`);
458
+ }
459
+ }
460
+ if (config.eventAppRoles && config.eventAppRoles.length > 0 && eventId && appId) {
461
+ const { isEventAdmin } = await import('./api-Y4MQWOFW.js');
462
+ const isEventAdminUser = await isEventAdmin(userId, { organisationId, eventId, appId });
463
+ if (!isEventAdminUser && config.requireAll !== false) {
464
+ throw new Error(`Event admin role required`);
465
+ }
466
+ }
467
+ if (organisationId) {
468
+ const { emitAuditEvent: emitAuditEvent2 } = await import('./audit-MYQXYZFU.js');
469
+ await emitAuditEvent2({
470
+ type: "permission_check",
471
+ userId,
472
+ organisationId,
473
+ eventId,
474
+ appId,
475
+ permission: "role:check",
476
+ decision: true,
477
+ source: "api",
478
+ bypass: false,
479
+ duration_ms: 0,
480
+ metadata: {
481
+ operation: "role_guard"
482
+ }
483
+ });
484
+ }
485
+ return handler(...args);
486
+ };
487
+ }
488
+ function createRBACMiddleware(config) {
489
+ return async (req, res, next) => {
490
+ const { pathname } = req.nextUrl;
491
+ const userId = req.user?.id;
492
+ const organisationId = req.organisationId;
493
+ if (!userId || !organisationId) {
494
+ return res.redirect(config.fallbackUrl || "/login");
495
+ }
496
+ const protectedRoute = config.protectedRoutes.find(
497
+ (route) => pathname.startsWith(route.path)
498
+ );
499
+ if (protectedRoute) {
500
+ try {
501
+ const { isPermitted: isPermitted2 } = await import('./api-Y4MQWOFW.js');
502
+ const hasPermission = await isPermitted2({
503
+ userId,
504
+ scope: { organisationId },
505
+ permission: protectedRoute.permission,
506
+ pageId: protectedRoute.pageId
507
+ });
508
+ if (!hasPermission) {
509
+ return res.redirect(config.fallbackUrl || "/access-denied");
510
+ }
511
+ } catch (_error) {
512
+ return res.redirect(config.fallbackUrl || "/access-denied");
513
+ }
514
+ }
515
+ next();
516
+ };
517
+ }
518
+ function createRBACExpressMiddleware(config) {
519
+ return async (req, res, next) => {
520
+ const userId = req.user?.id;
521
+ const organisationId = req.organisationId;
522
+ const eventId = req.eventId;
523
+ const appId = req.appId;
524
+ if (!userId || !organisationId) {
525
+ return res.status(401).json({ error: "User context required" });
526
+ }
527
+ try {
528
+ const { isPermitted: isPermitted2 } = await import('./api-Y4MQWOFW.js');
529
+ const hasPermission = await isPermitted2({
530
+ userId,
531
+ scope: { organisationId, eventId, appId },
532
+ permission: config.permission,
533
+ pageId: config.pageId
534
+ });
535
+ if (!hasPermission) {
536
+ return res.status(403).json({ error: "Permission denied" });
537
+ }
538
+ next();
539
+ } catch (_error) {
540
+ return res.status(500).json({ error: "Permission check failed" });
541
+ }
542
+ };
543
+ }
544
+
545
+ // src/rbac/permissions.ts
546
+ createLogger("RBACPermissions");
547
+ var GLOBAL_PERMISSIONS = {
548
+ READ_ALL: "read:*",
549
+ CREATE_ALL: "create:*",
550
+ UPDATE_ALL: "update:*",
551
+ DELETE_ALL: "delete:*"
552
+ };
553
+ var ORGANISATION_PERMISSIONS = {
554
+ // Organisation management
555
+ READ_ORGANISATION: "read:organisation",
556
+ UPDATE_ORGANISATION: "update:organisation",
557
+ DELETE_ORGANISATION: "delete:organisation",
558
+ // User management
559
+ READ_USERS: "read:users",
560
+ CREATE_USERS: "create:users",
561
+ UPDATE_USERS: "update:users",
562
+ DELETE_USERS: "delete:users",
563
+ // Role management
564
+ READ_ROLES: "read:roles",
565
+ CREATE_ROLES: "create:roles",
566
+ UPDATE_ROLES: "update:roles",
567
+ DELETE_ROLES: "delete:roles",
568
+ // Event management
569
+ READ_EVENTS: "read:events",
570
+ CREATE_EVENTS: "create:events",
571
+ UPDATE_EVENTS: "update:events",
572
+ DELETE_EVENTS: "delete:events",
573
+ // App management
574
+ READ_APPS: "read:apps",
575
+ CREATE_APPS: "create:apps",
576
+ UPDATE_APPS: "update:apps",
577
+ DELETE_APPS: "delete:apps"
578
+ };
579
+ var EVENT_APP_PERMISSIONS = {
580
+ // Event management
581
+ READ_EVENT: "read:event",
582
+ CREATE_EVENT: "create:event",
583
+ UPDATE_EVENT: "update:event",
584
+ DELETE_EVENT: "delete:event",
585
+ // App management
586
+ READ_APP: "read:app",
587
+ CREATE_APP: "create:app",
588
+ UPDATE_APP: "update:app",
589
+ DELETE_APP: "delete:app",
590
+ // Team management
591
+ READ_TEAM: "read:team",
592
+ CREATE_TEAM: "create:team",
593
+ UPDATE_TEAM: "update:team",
594
+ DELETE_TEAM: "delete:team",
595
+ // Team members
596
+ READ_TEAM_MEMBERS: "read:team.members",
597
+ CREATE_TEAM_MEMBERS: "create:team.members",
598
+ UPDATE_TEAM_MEMBERS: "update:team.members",
599
+ DELETE_TEAM_MEMBERS: "delete:team.members",
600
+ // Event content
601
+ READ_EVENT_CONTENT: "read:event.content",
602
+ CREATE_EVENT_CONTENT: "create:event.content",
603
+ UPDATE_EVENT_CONTENT: "update:event.content",
604
+ DELETE_EVENT_CONTENT: "delete:event.content",
605
+ // Event settings
606
+ READ_EVENT_SETTINGS: "read:event.settings",
607
+ CREATE_EVENT_SETTINGS: "create:event.settings",
608
+ UPDATE_EVENT_SETTINGS: "update:event.settings",
609
+ DELETE_EVENT_SETTINGS: "delete:event.settings"
610
+ };
611
+ var PAGE_PERMISSIONS = {
612
+ // General page access (generic - used for wildcard checks)
613
+ READ_PAGE: "read:page",
614
+ CREATE_PAGE: "create:page",
615
+ UPDATE_PAGE: "update:page",
616
+ DELETE_PAGE: "delete:page",
617
+ // Admin pages
618
+ READ_ADMIN: "read:page.admin",
619
+ CREATE_ADMIN: "create:page.admin",
620
+ UPDATE_ADMIN: "update:page.admin",
621
+ DELETE_ADMIN: "delete:page.admin",
622
+ // Dashboard pages
623
+ READ_DASHBOARD: "read:page.dashboard",
624
+ CREATE_DASHBOARD: "create:page.dashboard",
625
+ UPDATE_DASHBOARD: "update:page.dashboard",
626
+ DELETE_DASHBOARD: "delete:page.dashboard",
627
+ // Settings pages
628
+ READ_SETTINGS: "read:page.settings",
629
+ CREATE_SETTINGS: "create:page.settings",
630
+ UPDATE_SETTINGS: "update:page.settings",
631
+ DELETE_SETTINGS: "delete:page.settings",
632
+ // Reports pages
633
+ READ_REPORTS: "read:page.reports",
634
+ CREATE_REPORTS: "create:page.reports",
635
+ UPDATE_REPORTS: "update:page.reports",
636
+ DELETE_REPORTS: "delete:page.reports"
637
+ };
638
+ function isValidPermission(permission) {
639
+ const pattern = /^(read|create|update|delete):[a-z0-9]+(\.[a-z0-9]+)*$|^(read|create|update|delete):\*$/;
640
+ return pattern.test(permission);
641
+ }
642
+ var ALL_PERMISSIONS = {
643
+ ...GLOBAL_PERMISSIONS,
644
+ ...ORGANISATION_PERMISSIONS,
645
+ ...EVENT_APP_PERMISSIONS,
646
+ ...PAGE_PERMISSIONS
647
+ };
648
+
649
+ // src/rbac/compliance/setup-validator.ts
650
+ function isRBACInitialized() {
651
+ try {
652
+ const config = getRBACConfig();
653
+ return config !== null && config.supabase !== null;
654
+ } catch (error) {
655
+ if (error instanceof RBACNotInitializedError) {
656
+ return false;
657
+ }
658
+ throw error;
659
+ }
660
+ }
661
+ function getSetupIssues() {
662
+ const issues = [];
663
+ const config = getRBACConfig();
664
+ if (!config) {
665
+ issues.push({
666
+ type: "not-initialized",
667
+ message: "RBAC system has not been initialized. setupRBAC() has not been called.",
668
+ recommendation: "Call setupRBAC(supabase) before using any RBAC features. This should be done in your main entry point (main.tsx or App.tsx) before rendering the app."
669
+ });
670
+ return issues;
671
+ }
672
+ if (!config.supabase) {
673
+ issues.push({
674
+ type: "missing-config",
675
+ message: "RBAC configuration is missing Supabase client.",
676
+ recommendation: "Ensure setupRBAC() is called with a valid Supabase client instance."
677
+ });
678
+ }
679
+ return issues;
680
+ }
681
+ function getProviderContextIssues() {
682
+ const issues = [];
683
+ if (!isRBACInitialized()) {
684
+ issues.push({
685
+ type: "not-initialized",
686
+ message: "RBAC system must be initialized before provider context can be used.",
687
+ recommendation: "Call setupRBAC(supabase) before rendering UnifiedAuthProvider."
688
+ });
689
+ }
690
+ return issues;
691
+ }
692
+ function validateRBACSetup() {
693
+ const issues = getSetupIssues();
694
+ const providerIssues = getProviderContextIssues();
695
+ return {
696
+ isCompliant: issues.length === 0 && providerIssues.length === 0,
697
+ issues: [...issues, ...providerIssues]
698
+ };
699
+ }
700
+
701
+ // src/rbac/compliance/runtime-compliance.ts
702
+ function checkRuntimeCompliance() {
703
+ const logger = getRBACLogger();
704
+ const setupValidation = validateRBACSetup();
705
+ const warnings = [];
706
+ if (!setupValidation.isCompliant) {
707
+ setupValidation.issues.forEach((issue) => {
708
+ const warning = `[RBAC Compliance] ${issue.message}
709
+ Recommendation: ${issue.recommendation}`;
710
+ warnings.push(warning);
711
+ logger.warn(warning);
712
+ });
713
+ }
714
+ const providerContextIssues = setupValidation.issues.filter(
715
+ (issue) => issue.type === "missing-provider-context" || issue.type === "not-initialized"
716
+ );
717
+ const providerContext = providerContextIssues.length > 0 ? {
718
+ available: false,
719
+ message: "UnifiedAuthProvider context may not be available. Ensure your app is wrapped with UnifiedAuthProvider from @jmruthers/pace-core."
720
+ } : {
721
+ available: true
722
+ };
723
+ return {
724
+ setup: setupValidation,
725
+ warnings,
726
+ providerContext
727
+ };
728
+ }
729
+ function validateAndWarn() {
730
+ if (import.meta.env.MODE === "development" || import.meta.env.DEV) {
731
+ checkRuntimeCompliance();
732
+ }
733
+ }
734
+
735
+ // src/rbac/compliance/database-validator.ts
736
+ async function validateDatabaseConfiguration(supabase, appName) {
737
+ const issues = [];
738
+ const recommendations = [];
739
+ let appConfigured = false;
740
+ let pagesConfigured = false;
741
+ let permissionsConfigured = false;
742
+ let rlsPoliciesActive = false;
743
+ let rolesConfigured = false;
744
+ try {
745
+ const { data: app, error: appError } = await supabase.from("rbac_apps").select("id, name").eq("name", appName).single();
746
+ if (appError || !app) {
747
+ issues.push({
748
+ type: "app-not-configured",
749
+ message: `App '${appName}' not found in rbac_apps table.`,
750
+ recommendation: `Register your app in the rbac_apps table with name '${appName}' (case-sensitive).`
751
+ });
752
+ } else {
753
+ appConfigured = true;
754
+ if (app.name !== appName) {
755
+ issues.push({
756
+ type: "app-name-mismatch",
757
+ message: `App name mismatch. Database has '${app.name}', but environment variable has '${appName}'.`,
758
+ recommendation: `Ensure VITE_APP_NAME (or NEXT_PUBLIC_APP_NAME) matches the app name in rbac_apps table exactly (case-sensitive).`
759
+ });
760
+ }
761
+ const { data: pages, error: pagesError } = await supabase.from("rbac_app_pages").select("id").eq("app_id", app.id).limit(1);
762
+ if (pagesError || !pages || pages.length === 0) {
763
+ issues.push({
764
+ type: "pages-not-configured",
765
+ message: `No pages found for app '${appName}' in rbac_app_pages table.`,
766
+ recommendation: "Register your app pages in the rbac_app_pages table. Each route/page should have an entry."
767
+ });
768
+ } else {
769
+ pagesConfigured = true;
770
+ const { data: permissions, error: permissionsError } = await supabase.from("rbac_page_permissions").select("id").in("page_id", pages.map((p) => p.id)).limit(1);
771
+ if (permissionsError || !permissions || permissions.length === 0) {
772
+ issues.push({
773
+ type: "permissions-not-configured",
774
+ message: `No permissions found for app '${appName}' pages in rbac_page_permissions table.`,
775
+ recommendation: "Configure permissions for your app pages in the rbac_page_permissions table. Each page should have permissions for different operations (read, create, update, delete)."
776
+ });
777
+ } else {
778
+ permissionsConfigured = true;
779
+ }
780
+ }
781
+ }
782
+ try {
783
+ const { data: rbacTables, error: rlsError } = await supabase.rpc("rbac_check_rls_status");
784
+ if (rlsError) {
785
+ rlsPoliciesActive = true;
786
+ recommendations.push("Consider adding an RLS status check function to validate RLS policies are active.");
787
+ } else {
788
+ rlsPoliciesActive = true;
789
+ }
790
+ } catch (error) {
791
+ rlsPoliciesActive = true;
792
+ recommendations.push("Consider adding an RLS status check function to validate RLS policies are active.");
793
+ }
794
+ const { data: orgRoles, error: rolesError } = await supabase.from("rbac_organisation_roles").select("id").limit(1);
795
+ if (rolesError) {
796
+ issues.push({
797
+ type: "roles-not-configured",
798
+ message: "Unable to query rbac_organisation_roles table. RLS might be blocking access or table might not exist.",
799
+ recommendation: "Ensure rbac_organisation_roles table exists and RLS policies allow read access for authenticated users."
800
+ });
801
+ } else {
802
+ rolesConfigured = true;
803
+ }
804
+ } catch (error) {
805
+ issues.push({
806
+ type: "app-not-configured",
807
+ message: `Error validating database configuration: ${error instanceof Error ? error.message : "Unknown error"}`,
808
+ recommendation: "Check your Supabase connection and ensure you have the necessary permissions to query RBAC tables."
809
+ });
810
+ }
811
+ return {
812
+ appConfigured,
813
+ pagesConfigured,
814
+ permissionsConfigured,
815
+ rlsPoliciesActive,
816
+ rolesConfigured,
817
+ issues,
818
+ recommendations
819
+ };
820
+ }
821
+
822
+ // src/rbac/compliance/quick-fix-suggestions.ts
823
+ function getCustomAuthCodeFixes(customCodeName, type) {
824
+ const fixes = {
825
+ "useAuth": {
826
+ issue: `Custom ${type} '${customCodeName}' detected`,
827
+ suggestion: `Replace with useUnifiedAuth from pace-core`,
828
+ codeExample: `// Before
829
+ import { useAuth } from './hooks/useAuth';
830
+
831
+ // After
832
+ import { useUnifiedAuth } from '@jmruthers/pace-core';`,
833
+ migrationSteps: [
834
+ "Remove custom useAuth hook",
835
+ "Import useUnifiedAuth from @jmruthers/pace-core",
836
+ "Update all usages to use useUnifiedAuth",
837
+ "Ensure UnifiedAuthProvider wraps your app"
838
+ ]
839
+ },
840
+ "usePermissions": {
841
+ issue: `Custom ${type} '${customCodeName}' detected`,
842
+ suggestion: `Replace with usePermissions from pace-core`,
843
+ codeExample: `// Before
844
+ import { usePermissions } from './hooks/usePermissions';
845
+
846
+ // After
847
+ import { usePermissions } from '@jmruthers/pace-core/rbac';`,
848
+ migrationSteps: [
849
+ "Remove custom usePermissions hook",
850
+ "Import usePermissions from @jmruthers/pace-core/rbac",
851
+ "Update all usages - ensure setupRBAC() has been called",
852
+ "Verify provider hierarchy is correct"
853
+ ]
854
+ },
855
+ "PermissionGuard": {
856
+ issue: `Custom ${type} '${customCodeName}' detected`,
857
+ suggestion: `Replace with PagePermissionGuard from pace-core`,
858
+ codeExample: `// Before
859
+ import { PermissionGuard } from './components/PermissionGuard';
860
+
861
+ // After
862
+ import { PagePermissionGuard } from '@jmruthers/pace-core/rbac';`,
863
+ migrationSteps: [
864
+ "Remove custom PermissionGuard component",
865
+ "Import PagePermissionGuard from @jmruthers/pace-core/rbac",
866
+ "Wrap pages with PagePermissionGuard",
867
+ "Use pageName and operation props instead of custom permission strings"
868
+ ]
869
+ },
870
+ "checkPermission": {
871
+ issue: `Custom ${type} '${customCodeName}' detected`,
872
+ suggestion: `Replace with isPermitted from pace-core`,
873
+ codeExample: `// Before
874
+ import { checkPermission } from './utils/permissions';
875
+
876
+ // After
877
+ import { isPermitted } from '@jmruthers/pace-core/rbac';`,
878
+ migrationSteps: [
879
+ "Remove custom checkPermission utility",
880
+ "Import isPermitted from @jmruthers/pace-core/rbac",
881
+ "Update all usages to use isPermitted with proper scope",
882
+ "Ensure setupRBAC() has been called"
883
+ ]
884
+ }
885
+ };
886
+ return fixes[customCodeName] || {
887
+ issue: `Custom ${type} '${customCodeName}' detected`,
888
+ suggestion: `Use pace-core's equivalent instead. Check @jmruthers/pace-core documentation for the correct import.`,
889
+ migrationSteps: [
890
+ `Remove custom ${customCodeName} ${type}`,
891
+ "Find equivalent in pace-core",
892
+ "Import from @jmruthers/pace-core or @jmruthers/pace-core/rbac",
893
+ "Update all usages"
894
+ ]
895
+ };
896
+ }
897
+ function getDuplicateConfigFixes() {
898
+ return {
899
+ issue: "Multiple Supabase client instantiations found",
900
+ suggestion: "Consolidate to a single Supabase client configuration",
901
+ codeExample: `// Before - Multiple createClient calls
902
+ // src/lib/supabase.ts
903
+ export const supabase = createClient(url, key);
904
+
905
+ // src/utils/api.ts
906
+ export const supabase = createClient(url, key);
907
+
908
+ // After - Single configuration
909
+ // src/lib/supabase.ts
910
+ export const supabase = createClient(
911
+ import.meta.env.VITE_SUPABASE_URL,
912
+ import.meta.env.VITE_SUPABASE_PUBLISHABLE_KEY
913
+ );
914
+
915
+ // src/utils/api.ts
916
+ import { supabase } from '../lib/supabase';`,
917
+ migrationSteps: [
918
+ "Create a single supabase.ts file in a shared location (e.g., src/lib/supabase.ts)",
919
+ "Move all Supabase client creation to this file",
920
+ "Export the client instance",
921
+ "Update all files to import from the shared location",
922
+ "Remove duplicate createClient calls"
923
+ ]
924
+ };
925
+ }
926
+ function getUnprotectedPageFixes() {
927
+ return {
928
+ issue: "Route/page found without PagePermissionGuard",
929
+ suggestion: "Wrap all routes with PagePermissionGuard",
930
+ codeExample: `// Before
931
+ <Route path="/dashboard" element={<Dashboard />} />
932
+
933
+ // After
934
+ <Route
935
+ path="/dashboard"
936
+ element={
937
+ <PagePermissionGuard pageName="dashboard" operation="read">
938
+ <Dashboard />
939
+ </PagePermissionGuard>
940
+ }
941
+ />`,
942
+ migrationSteps: [
943
+ "Import PagePermissionGuard from @jmruthers/pace-core/rbac",
944
+ "Wrap each route/page component with PagePermissionGuard",
945
+ "Set pageName prop to match your page name in rbac_app_pages table",
946
+ "Set operation prop (read, create, update, or delete)",
947
+ "Ensure setupRBAC() has been called and providers are set up correctly"
948
+ ]
949
+ };
950
+ }
951
+ function getDirectSupabaseAuthFixes() {
952
+ return {
953
+ issue: "Direct Supabase auth usage detected",
954
+ suggestion: "Use UnifiedAuthProvider and useUnifiedAuth from pace-core",
955
+ codeExample: `// Before
956
+ import { createClient } from '@supabase/supabase-js';
957
+ const supabase = createClient(url, key);
958
+ await supabase.auth.signInWithPassword({ email, password });
959
+
960
+ // After
961
+ import { useUnifiedAuth } from '@jmruthers/pace-core';
962
+ const { signIn } = useUnifiedAuth();
963
+ await signIn({ email, password });`,
964
+ migrationSteps: [
965
+ "Remove direct Supabase auth calls",
966
+ "Import useUnifiedAuth from @jmruthers/pace-core",
967
+ "Use the auth methods from useUnifiedAuth hook",
968
+ "Ensure UnifiedAuthProvider wraps your app",
969
+ "Update all auth-related code to use pace-core hooks"
970
+ ]
971
+ };
972
+ }
973
+ function getQuickFixes(issueType, details) {
974
+ const fixes = [];
975
+ switch (issueType) {
976
+ case "custom-auth-code":
977
+ if (details?.name && details?.type) {
978
+ fixes.push(getCustomAuthCodeFixes(details.name, details.type));
979
+ }
980
+ break;
981
+ case "duplicate-config":
982
+ fixes.push(getDuplicateConfigFixes());
983
+ break;
984
+ case "unprotected-pages":
985
+ fixes.push(getUnprotectedPageFixes());
986
+ break;
987
+ case "direct-supabase-auth":
988
+ fixes.push(getDirectSupabaseAuthFixes());
989
+ break;
990
+ }
991
+ return fixes;
992
+ }
993
+
994
+ export { ALL_PERMISSIONS, EVENT_APP_PERMISSIONS, GLOBAL_PERMISSIONS, NavigationGuard, ORGANISATION_PERMISSIONS, PAGE_PERMISSIONS, PagePermissionGuard, RBACErrorCode, RPCFunction, checkRuntimeCompliance, createRBACExpressMiddleware, createRBACMiddleware, getCustomAuthCodeFixes, getDirectSupabaseAuthFixes, getDuplicateConfigFixes, getQuickFixes, getSetupIssues, getUnprotectedPageFixes, isRBACInitialized, isValidPermission, validateAndWarn, validateDatabaseConfiguration, validateRBACSetup, withAccessLevelGuard, withPermissionGuard, withRoleGuard };