@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
@@ -1,18 +0,0 @@
1
- import {
2
- UnifiedAuthContext,
3
- UnifiedAuthProvider,
4
- useUnifiedAuth
5
- } from "./chunk-AVMLPIM7.js";
6
- import "./chunk-3LPHPB62.js";
7
- import "./chunk-63FOKYGO.js";
8
- import "./chunk-36LVWXB2.js";
9
- import "./chunk-QXHPKYJV.js";
10
- import "./chunk-VBXEHIUJ.js";
11
- import "./chunk-PWLANIRT.js";
12
- import "./chunk-DGUM43GV.js";
13
- export {
14
- UnifiedAuthContext,
15
- UnifiedAuthProvider,
16
- useUnifiedAuth
17
- };
18
- //# sourceMappingURL=UnifiedAuthProvider-QPXO24B4.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,52 +0,0 @@
1
- import {
2
- clearCache,
3
- getAccessLevel,
4
- getPageScopeType,
5
- getPermissionMap,
6
- getRoleContext,
7
- hasAllPermissions,
8
- hasAnyPermission,
9
- hasPermission,
10
- invalidateAppCache,
11
- invalidateEventCache,
12
- invalidateOrganisationCache,
13
- invalidateUserCache,
14
- isEventAdmin,
15
- isOrganisationAdmin,
16
- isPermitted,
17
- isPermittedCached,
18
- isRBACInitialized,
19
- isSuperAdmin,
20
- resolveAppContext,
21
- setupRBAC
22
- } from "./chunk-3LPHPB62.js";
23
- import "./chunk-63FOKYGO.js";
24
- import {
25
- OrganisationContextRequiredError
26
- } from "./chunk-36LVWXB2.js";
27
- import "./chunk-PWLANIRT.js";
28
- import "./chunk-DGUM43GV.js";
29
- export {
30
- OrganisationContextRequiredError,
31
- clearCache,
32
- getAccessLevel,
33
- getPageScopeType,
34
- getPermissionMap,
35
- getRoleContext,
36
- hasAllPermissions,
37
- hasAnyPermission,
38
- hasPermission,
39
- invalidateAppCache,
40
- invalidateEventCache,
41
- invalidateOrganisationCache,
42
- invalidateUserCache,
43
- isEventAdmin,
44
- isOrganisationAdmin,
45
- isPermitted,
46
- isPermittedCached,
47
- isRBACInitialized,
48
- isSuperAdmin,
49
- resolveAppContext,
50
- setupRBAC
51
- };
52
- //# sourceMappingURL=api-6LVZTHDS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,17 +0,0 @@
1
- import {
2
- RBACAuditManager,
3
- createAuditManager,
4
- emitAuditEvent,
5
- getGlobalAuditManager,
6
- setGlobalAuditManager
7
- } from "./chunk-63FOKYGO.js";
8
- import "./chunk-PWLANIRT.js";
9
- import "./chunk-DGUM43GV.js";
10
- export {
11
- RBACAuditManager,
12
- createAuditManager,
13
- emitAuditEvent,
14
- getGlobalAuditManager,
15
- setGlobalAuditManager
16
- };
17
- //# sourceMappingURL=audit-V53FV5AG.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -1,227 +0,0 @@
1
- import {
2
- createLogger
3
- } from "./chunk-PWLANIRT.js";
4
-
5
- // src/rbac/types.ts
6
- var RBACError = class extends Error {
7
- constructor(message, code, context) {
8
- super(message);
9
- this.code = code;
10
- this.context = context;
11
- this.name = "RBACError";
12
- }
13
- };
14
- var PermissionDeniedError = class extends RBACError {
15
- constructor(permission, context) {
16
- super(
17
- `Permission denied: ${permission}`,
18
- "PERMISSION_DENIED",
19
- { permission, ...context }
20
- );
21
- this.name = "PermissionDeniedError";
22
- }
23
- };
24
- var OrganisationContextRequiredError = class extends RBACError {
25
- constructor() {
26
- super(
27
- "Organisation context is required for this operation",
28
- "ORGANISATION_CONTEXT_REQUIRED"
29
- );
30
- this.name = "OrganisationContextRequiredError";
31
- }
32
- };
33
- var EventContextRequiredError = class extends RBACError {
34
- constructor() {
35
- super(
36
- "Event context is required for this operation",
37
- "EVENT_CONTEXT_REQUIRED"
38
- );
39
- this.name = "EventContextRequiredError";
40
- }
41
- };
42
- var RBACNotInitializedError = class extends RBACError {
43
- constructor() {
44
- super(
45
- "RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup",
46
- "RBAC_NOT_INITIALIZED"
47
- );
48
- this.name = "RBACNotInitializedError";
49
- }
50
- };
51
- var InvalidScopeError = class extends RBACError {
52
- constructor(scope, reason) {
53
- super(
54
- `Invalid scope provided: ${JSON.stringify(scope)}. ${reason}`,
55
- "INVALID_SCOPE",
56
- { scope, reason }
57
- );
58
- this.name = "InvalidScopeError";
59
- }
60
- };
61
- var MissingUserContextError = class extends RBACError {
62
- constructor() {
63
- super(
64
- "User context is required but not available. Make sure to wrap your app with an auth provider.",
65
- "MISSING_USER_CONTEXT"
66
- );
67
- this.name = "MissingUserContextError";
68
- }
69
- };
70
-
71
- // src/rbac/utils/eventContext.ts
72
- var orgDerivationCache = /* @__PURE__ */ new Map();
73
- var MAX_CACHE_SIZE = 100;
74
- async function getOrganisationFromEvent(supabase, eventId) {
75
- if (orgDerivationCache.has(eventId)) {
76
- return orgDerivationCache.get(eventId) ?? null;
77
- }
78
- const { data, error } = await supabase.from("core_events").select("organisation_id").eq("event_id", eventId).single();
79
- let organisationId = null;
80
- if (error || !data) {
81
- organisationId = null;
82
- } else if (data.organisation_id) {
83
- organisationId = data.organisation_id;
84
- } else {
85
- organisationId = null;
86
- }
87
- if (orgDerivationCache.size >= MAX_CACHE_SIZE) {
88
- const firstKey = orgDerivationCache.keys().next().value;
89
- if (firstKey) {
90
- orgDerivationCache.delete(firstKey);
91
- }
92
- }
93
- orgDerivationCache.set(eventId, organisationId);
94
- return organisationId;
95
- }
96
-
97
- // src/rbac/utils/contextValidator.ts
98
- var log = createLogger("ContextValidator");
99
- var ContextValidator = class {
100
- /**
101
- * Derive organisation ID from event ID
102
- *
103
- * @param supabase - Supabase client
104
- * @param eventId - Event ID
105
- * @returns Organisation ID or null
106
- */
107
- static async deriveOrgFromEvent(supabase, eventId) {
108
- return getOrganisationFromEvent(supabase, eventId);
109
- }
110
- /**
111
- * Resolve scope based on page-level scope_type
112
- *
113
- * This method handles page-level scoping. All pages have explicit scope_type set.
114
- * Used for hybrid apps like pace-mint that have both event and organisation pages.
115
- *
116
- * @param scope - Current scope
117
- * @param pageScopeType - Page scope type ('event', 'organisation', or 'both')
118
- * @param appName - App name (for PORTAL/ADMIN special case)
119
- * @param supabase - Supabase client (for deriving org from event)
120
- * @returns Resolved scope with all required context
121
- */
122
- static async resolveScopeForPage(scope, pageScopeType, appName, supabase) {
123
- const effectiveScopeType = pageScopeType;
124
- if (effectiveScopeType === "both") {
125
- if (!scope.organisationId && !scope.eventId) {
126
- return {
127
- isValid: false,
128
- resolvedScope: null,
129
- error: new Error("Page requires either organisation or event context")
130
- };
131
- }
132
- let organisationId = scope.organisationId;
133
- if (!organisationId && scope.eventId && supabase) {
134
- try {
135
- const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
136
- organisationId = derivedOrgId || void 0;
137
- } catch (error) {
138
- log.warn("Failed to derive org from event for both-scope page:", error);
139
- }
140
- }
141
- return {
142
- isValid: true,
143
- resolvedScope: {
144
- organisationId,
145
- eventId: scope.eventId,
146
- appId: scope.appId
147
- },
148
- error: null
149
- };
150
- }
151
- if (effectiveScopeType === "event") {
152
- if (!scope.eventId) {
153
- return {
154
- isValid: false,
155
- resolvedScope: null,
156
- error: new EventContextRequiredError()
157
- };
158
- }
159
- let organisationId = scope.organisationId;
160
- if (!organisationId && supabase && scope.eventId) {
161
- try {
162
- const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);
163
- organisationId = derivedOrgId || void 0;
164
- if (!organisationId) {
165
- return {
166
- isValid: false,
167
- resolvedScope: null,
168
- error: new Error("Could not resolve organisation from event context")
169
- };
170
- }
171
- } catch (error) {
172
- log.error("Failed to derive org from event:", error);
173
- return {
174
- isValid: false,
175
- resolvedScope: null,
176
- error: error instanceof Error ? error : new Error("Failed to derive organisation from event")
177
- };
178
- }
179
- }
180
- return {
181
- isValid: true,
182
- resolvedScope: {
183
- organisationId,
184
- eventId: scope.eventId,
185
- appId: scope.appId
186
- },
187
- error: null
188
- };
189
- }
190
- if (effectiveScopeType === "organisation") {
191
- if (!scope.organisationId) {
192
- return {
193
- isValid: false,
194
- resolvedScope: null,
195
- error: new OrganisationContextRequiredError()
196
- };
197
- }
198
- return {
199
- isValid: true,
200
- resolvedScope: {
201
- organisationId: scope.organisationId,
202
- eventId: scope.eventId,
203
- // Event is optional for org-scoped pages
204
- appId: scope.appId
205
- },
206
- error: null
207
- };
208
- }
209
- return {
210
- isValid: false,
211
- resolvedScope: null,
212
- error: new Error("Invalid scope type")
213
- };
214
- }
215
- };
216
-
217
- export {
218
- RBACError,
219
- PermissionDeniedError,
220
- OrganisationContextRequiredError,
221
- EventContextRequiredError,
222
- RBACNotInitializedError,
223
- InvalidScopeError,
224
- MissingUserContextError,
225
- ContextValidator
226
- };
227
- //# sourceMappingURL=chunk-36LVWXB2.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/rbac/types.ts","../src/rbac/utils/eventContext.ts","../src/rbac/utils/contextValidator.ts"],"sourcesContent":["/**\n * RBAC (Role-Based Access Control) Types - Build Contract Compliant\n * @package @jmruthers/pace-core\n * @module RBAC/Types\n * @since 1.0.0\n * \n * This module defines the core types for the RBAC system that match the build contract exactly.\n * All types are designed to be framework-agnostic and provide strong typing for permission operations.\n */\n\nimport type React from 'react';\nimport type { AppId, PageId } from '../types/core';\n\n// ============================================================================\n// CORE TYPES\n// ============================================================================\n\nexport type UUID = string;\n\nexport type Operation = 'read' | 'create' | 'update' | 'delete';\n\nexport type Permission = `${Operation}:${string}`; // e.g. \"read:base.events\" or \"create:team.members\"\n\nexport type AccessLevel =\n | 'viewer'\n | 'participant'\n | 'planner'\n | 'admin'\n | 'super';\n\n/**\n * Scope defines the context for permission checks.\n * Can include organisation, event, and/or app identifiers.\n */\nexport type Scope = {\n organisationId?: UUID;\n eventId?: string; // event_id is text/varchar\n appId?: AppId | UUID;\n};\n\n/**\n * Permission check request parameters.\n * Defines who (userId) is checking what permission in what context (scope).\n */\nexport type PermissionCheck = {\n userId: UUID;\n scope: Scope;\n permission: Permission;\n pageId?: PageId | UUID;\n};\n\nexport type PermissionMap = Record<Permission, boolean> & Partial<Record<'*', boolean>>;\n\n// ============================================================================\n// ROLE TYPES\n// ============================================================================\n\nexport type GlobalRole = 'super_admin';\n\nexport type OrganisationRole = 'supporter' | 'member' | 'leader' | 'org_admin';\n\nexport type EventAppRole = 'viewer' | 'participant' | 'planner' | 'event_admin';\n\n// ============================================================================\n// DATABASE TYPES\n// ============================================================================\n\nexport interface RBACGlobalRole {\n id: UUID;\n user_id: UUID;\n role: GlobalRole;\n granted_at: string;\n granted_by: UUID | null;\n valid_from: string;\n valid_to: string | null;\n}\n\nexport interface RBACOrganisationRole {\n id: UUID;\n user_id: UUID;\n organisation_id: UUID;\n role: OrganisationRole;\n status: 'active' | 'inactive' | 'suspended';\n granted_at: string;\n granted_by: UUID | null;\n revoked_at: string | null;\n revoked_by: UUID | null;\n notes: string | null;\n created_at: string;\n updated_at: string;\n valid_from: string;\n valid_to: string | null;\n}\n\nexport interface RBACEventAppRole {\n id: UUID;\n user_id: UUID;\n event_id: string;\n role: EventAppRole;\n status: 'active' | 'inactive' | 'suspended';\n granted_at: string;\n granted_by: UUID | null;\n organisation_id: UUID;\n app_id: UUID;\n valid_from: string;\n valid_to: string | null;\n}\n\nexport interface RBACPagePermission {\n id: UUID;\n app_page_id: UUID;\n operation: Operation;\n role_name: string;\n allowed: boolean;\n created_at: string;\n updated_at: string;\n organisation_id: UUID;\n}\n\nexport interface RBACAppPage {\n id: UUID;\n page_name: string;\n page_description: string | null;\n created_at: string;\n updated_at: string;\n created_by: UUID | null;\n updated_by: UUID | null;\n app_id: UUID;\n scope_type: 'event' | 'organisation' | 'both'; // Required - single source of truth for page scoping\n}\n\nexport interface RBACApp {\n id: UUID;\n name: string;\n display_name: string;\n description: string | null;\n requires_event: boolean;\n is_active: boolean;\n created_at: string;\n updated_at: string;\n created_by: UUID | null;\n updated_by: UUID | null;\n}\n\n// ============================================================================\n// AUDIT EVENT TYPES\n// ============================================================================\n\nexport type AuditEventType = \n | 'permission_check'\n | 'permission_denied'\n | 'role_granted'\n | 'role_denied'\n | 'rls_denied';\n\nexport type AuditEventSource = 'api' | 'ui' | 'middleware' | 'rls';\n\nexport interface RBACAuditEvent {\n id: UUID;\n event_type: AuditEventType;\n user_id: UUID;\n organisation_id: UUID | null; // Nullable to properly track missing context cases (should be rare since organisationId is required)\n event_id?: string;\n app_id?: UUID;\n page_id?: UUID;\n permission?: string;\n decision?: boolean;\n source?: AuditEventSource;\n bypass?: boolean;\n duration_ms?: number;\n metadata: Record<string, any>;\n created_at: string;\n}\n\nexport interface RBACAppContext {\n appId: UUID;\n hasAccess: boolean;\n}\n\nexport interface RBACRoleContext {\n globalRole: GlobalRole | null;\n organisationRole: OrganisationRole | null;\n eventAppRole: EventAppRole | null;\n}\n\n// ============================================================================\n// CACHE TYPES\n// ============================================================================\n\nexport interface CacheEntry<T> {\n data: T;\n expires: number;\n}\n\nexport interface PermissionCacheKey {\n userId: UUID;\n organisationId?: UUID;\n eventId?: string;\n appId?: UUID;\n permission?: Permission;\n pageId?: UUID | string;\n}\n\n// ============================================================================\n// API TYPES\n// ============================================================================\n\nexport interface GetAccessLevelInput {\n userId: UUID;\n scope: Scope;\n}\n\nexport interface GetPermissionMapInput {\n userId: UUID;\n scope: Scope;\n}\n\nexport interface IsPermittedInput extends PermissionCheck {}\n\n// ============================================================================\n// HOOK TYPES\n// ============================================================================\n\nexport interface UsePermissionsReturn {\n permissions: PermissionMap;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n}\n\nexport interface UseCanReturn {\n can: boolean;\n isLoading: boolean;\n error: Error | null;\n check: () => Promise<void>;\n}\n\n// ============================================================================\n// ADAPTER TYPES\n// ============================================================================\n\nexport interface PermissionGuardConfig {\n permission: Permission;\n pageId?: UUID;\n}\n\nexport interface WithPermissionGuardOptions {\n permission: Permission;\n pageId?: UUID;\n fallback?: React.ReactNode;\n onDenied?: () => void;\n}\n\n// ============================================================================\n// HOOK RETURN TYPES\n// ============================================================================\n\nexport interface UserRBACContext {\n user: any; // User from auth context\n globalRole: GlobalRole | null;\n organisationRole: OrganisationRole | null;\n eventAppRole: EventAppRole | null;\n hasGlobalPermission: (permission: Permission) => boolean;\n isSuperAdmin: boolean;\n isOrgAdmin: boolean;\n isEventAdmin: boolean;\n canManageOrganisation: boolean;\n canManageEvent: boolean;\n isLoading: boolean;\n error: Error | null;\n}\n\nexport interface RBACPermission {\n permission_type: string;\n role_name: string;\n [key: string]: any;\n}\n\n// ============================================================================\n// COMPONENT TYPES\n// ============================================================================\n\nexport interface RBACGuardProps {\n children: React.ReactNode;\n operation: Operation;\n pageId?: UUID;\n fallback?: React.ReactNode;\n}\n\nexport interface RoleBasedContentProps {\n children: React.ReactNode;\n globalRoles?: GlobalRole[];\n organisationRoles?: OrganisationRole[];\n eventAppRoles?: EventAppRole[];\n fallback?: React.ReactNode;\n}\n\n// ============================================================================\n// ERROR TYPES\n// ============================================================================\n\nexport class RBACError extends Error {\n constructor(\n message: string,\n public code: string,\n public context?: Record<string, any>\n ) {\n super(message);\n this.name = 'RBACError';\n }\n}\n\nexport class PermissionDeniedError extends RBACError {\n constructor(permission: Permission, context?: Record<string, any>) {\n super(\n `Permission denied: ${permission}`,\n 'PERMISSION_DENIED',\n { permission, ...context }\n );\n this.name = 'PermissionDeniedError';\n }\n}\n\nexport class OrganisationContextRequiredError extends RBACError {\n constructor() {\n super(\n 'Organisation context is required for this operation',\n 'ORGANISATION_CONTEXT_REQUIRED'\n );\n this.name = 'OrganisationContextRequiredError';\n }\n}\n\nexport class EventContextRequiredError extends RBACError {\n constructor() {\n super(\n 'Event context is required for this operation',\n 'EVENT_CONTEXT_REQUIRED'\n );\n this.name = 'EventContextRequiredError';\n }\n}\n\nexport class RBACNotInitializedError extends RBACError {\n constructor() {\n super(\n 'RBAC system not initialized. Please call setupRBAC(supabase) before using any RBAC components or hooks. See: https://docs.pace-core.dev/rbac/setup',\n 'RBAC_NOT_INITIALIZED'\n );\n this.name = 'RBACNotInitializedError';\n }\n}\n\nexport class InvalidScopeError extends RBACError {\n constructor(scope: Scope, reason: string) {\n super(\n `Invalid scope provided: ${JSON.stringify(scope)}. ${reason}`,\n 'INVALID_SCOPE',\n { scope, reason }\n );\n this.name = 'InvalidScopeError';\n }\n}\n\nexport class MissingUserContextError extends RBACError {\n constructor() {\n super(\n 'User context is required but not available. Make sure to wrap your app with an auth provider.',\n 'MISSING_USER_CONTEXT'\n );\n this.name = 'MissingUserContextError';\n }\n}\n","/**\n * Event Context Utilities for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/EventContext\n * @since 1.0.0\n * \n * This module provides utilities for event-based RBAC operations where\n * the organization context is derived from the event context.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\nimport { UUID, Scope } from '../types';\n\n/**\n * Cache for organisation derivation from event\n * Key: eventId, Value: organisationId | null\n * Maximum cache size to prevent memory leaks\n */\nconst orgDerivationCache = new Map<string, UUID | null>();\nconst MAX_CACHE_SIZE = 100; // Limit cache to 100 entries\n\n/**\n * Clear cache entry for a specific event (useful if event's org changes)\n * @param eventId - Event ID to clear from cache\n */\nexport function clearOrgDerivationCache(eventId: string): void {\n orgDerivationCache.delete(eventId);\n}\n\n/**\n * Clear all cached organisation derivations\n */\nexport function clearAllOrgDerivationCache(): void {\n orgDerivationCache.clear();\n}\n\n/**\n * Get organization ID from event ID\n * \n * Uses caching to avoid repeated database queries for the same event.\n * Cache is limited to prevent memory leaks.\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @returns Promise resolving to organization ID or null\n */\nexport async function getOrganisationFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string\n): Promise<UUID | null> {\n // Check cache first\n if (orgDerivationCache.has(eventId)) {\n return orgDerivationCache.get(eventId) ?? null;\n }\n\n // Query database\n const { data, error } = await supabase\n .from('core_events')\n .select('organisation_id')\n .eq('event_id', eventId)\n .single() as { data: { organisation_id: string } | null; error: any };\n\n let organisationId: UUID | null = null;\n\n if (error || !data) {\n organisationId = null;\n } else if (data.organisation_id) {\n organisationId = data.organisation_id;\n } else {\n // organisation_id is null or undefined\n organisationId = null;\n }\n\n // Cache the result (with size limit to prevent memory leaks)\n if (orgDerivationCache.size >= MAX_CACHE_SIZE) {\n // Remove oldest entry (first key in Map)\n const firstKey = orgDerivationCache.keys().next().value;\n if (firstKey) {\n orgDerivationCache.delete(firstKey);\n }\n }\n orgDerivationCache.set(eventId, organisationId);\n\n return organisationId;\n}\n\n/**\n * Create a complete scope from event context\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @param appId - Optional app ID\n * @returns Promise resolving to complete scope\n */\nexport async function createScopeFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string,\n appId?: UUID\n): Promise<Scope | null> {\n const organisationId = await getOrganisationFromEvent(supabase, eventId);\n \n if (!organisationId) {\n return null;\n }\n\n return {\n organisationId,\n eventId,\n appId\n };\n}\n\n/**\n * Check if a scope is event-based (has eventId but no explicit organisationId)\n * \n * @param scope - Permission scope\n * @returns True if scope is event-based\n */\nexport function isEventBasedScope(scope: Scope): boolean {\n return !scope.organisationId && !!scope.eventId;\n}\n\n/**\n * Validate that an event-based scope has the required context\n * \n * @param scope - Permission scope\n * @returns True if scope is valid for event-based operations\n */\nexport function isValidEventBasedScope(scope: Scope): boolean {\n return isEventBasedScope(scope) && !!scope.eventId;\n}\n","/**\n * Context Validator for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/ContextValidator\n * @since 1.0.0\n * \n * Centralized validation for RBAC context requirements based on app configuration.\n * Enforces app-specific context rules with single primary context:\n * - requires_event = TRUE: Event is PRIMARY context, org derived from event (org not required in input)\n * - requires_event = FALSE: Organisation is PRIMARY context, event optional\n * - PORTAL/ADMIN apps: Both contexts optional (allows users to view/edit own profiles, super admin access)\n * \n * Key principle: Only one primary context is required based on app config. The other is derived or optional.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\nimport { UUID, Scope } from '../types';\nimport { EventContextRequiredError, OrganisationContextRequiredError } from '../types';\nimport { getOrganisationFromEvent } from './eventContext';\nimport { createLogger } from '../../utils/core/logger';\n\nconst log = createLogger('ContextValidator');\n\n/**\n * Page scope type - determines what context is required for a page\n * This is the single source of truth for page scoping.\n */\nexport type PageScopeType = 'event' | 'organisation' | 'both';\n\n/**\n * Check if an app allows optional contexts (both organisation and event optional)\n * @param appName - App name to check\n * @returns True if app allows optional contexts\n */\nfunction allowsOptionalContexts(appName?: string): boolean {\n return appName === 'PORTAL' || appName === 'ADMIN';\n}\n\nexport interface ContextValidationResult {\n isValid: boolean;\n resolvedScope: Scope | null;\n error: Error | null;\n}\n\n/**\n * Context Validator class\n * \n * Validates and resolves RBAC scope based on app configuration requirements.\n */\nexport class ContextValidator {\n\n /**\n * Derive organisation ID from event ID\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @returns Organisation ID or null\n */\n static async deriveOrgFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string\n ): Promise<UUID | null> {\n return getOrganisationFromEvent(supabase, eventId);\n }\n\n /**\n * Resolve scope based on page-level scope_type\n * \n * This method handles page-level scoping. All pages have explicit scope_type set.\n * Used for hybrid apps like pace-mint that have both event and organisation pages.\n * \n * @param scope - Current scope\n * @param pageScopeType - Page scope type ('event', 'organisation', or 'both')\n * @param appName - App name (for PORTAL/ADMIN special case)\n * @param supabase - Supabase client (for deriving org from event)\n * @returns Resolved scope with all required context\n */\n static async resolveScopeForPage(\n scope: Scope,\n pageScopeType: PageScopeType,\n appName?: string,\n supabase?: SupabaseClient<Database> | null\n ): Promise<ContextValidationResult> {\n // Use page-level scope (single source of truth)\n const effectiveScopeType = pageScopeType;\n \n // Handle 'both' scope - requires both contexts available, but can use either\n if (effectiveScopeType === 'both') {\n // For 'both' pages, we need at least one context (org or event)\n // Both will be checked during permission evaluation\n if (!scope.organisationId && !scope.eventId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new Error('Page requires either organisation or event context')\n };\n }\n \n // Derive org from event if event is provided but org is not\n let organisationId = scope.organisationId;\n if (!organisationId && scope.eventId && supabase) {\n try {\n const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);\n organisationId = derivedOrgId || undefined;\n } catch (error) {\n log.warn('Failed to derive org from event for both-scope page:', error);\n // Continue without org - permission check will handle it\n }\n }\n \n return {\n isValid: true,\n resolvedScope: {\n organisationId,\n eventId: scope.eventId,\n appId: scope.appId\n },\n error: null\n };\n }\n \n // Handle 'event' scope - requires event context\n if (effectiveScopeType === 'event') {\n if (!scope.eventId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new EventContextRequiredError()\n };\n }\n \n // Derive organisationId from event if not provided\n let organisationId: UUID | undefined = scope.organisationId;\n if (!organisationId && supabase && scope.eventId) {\n try {\n const derivedOrgId = await this.deriveOrgFromEvent(supabase, scope.eventId);\n organisationId = derivedOrgId || undefined;\n if (!organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new Error('Could not resolve organisation from event context')\n };\n }\n } catch (error) {\n log.error('Failed to derive org from event:', error);\n return {\n isValid: false,\n resolvedScope: null,\n error: error instanceof Error ? error : new Error('Failed to derive organisation from event')\n };\n }\n }\n \n return {\n isValid: true,\n resolvedScope: {\n organisationId,\n eventId: scope.eventId,\n appId: scope.appId\n },\n error: null\n };\n }\n \n // Handle 'organisation' scope - requires organisation context\n if (effectiveScopeType === 'organisation') {\n if (!scope.organisationId) {\n return {\n isValid: false,\n resolvedScope: null,\n error: new OrganisationContextRequiredError()\n };\n }\n \n return {\n isValid: true,\n resolvedScope: {\n organisationId: scope.organisationId,\n eventId: scope.eventId, // Event is optional for org-scoped pages\n appId: scope.appId\n },\n error: null\n };\n }\n \n // Fallback (should not happen)\n return {\n isValid: false,\n resolvedScope: null,\n error: new Error('Invalid scope type')\n };\n }\n\n}\n\n"],"mappings":"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","names":[]}