@jmruthers/pace-core 0.6.5 → 0.6.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -1,279 +0,0 @@
1
- /**
2
- * @file Page Permission Provider Component
3
- * @package @jmruthers/pace-core
4
- * @module RBAC/Components/PagePermissionProvider
5
- * @since 2.0.0
6
- *
7
- * A context provider that manages page-level permissions across the entire application.
8
- * This component ensures that all pages are properly protected and provides centralized
9
- * page permission management.
10
- *
11
- * Features:
12
- * - App-wide page permission management
13
- * - Strict mode to prevent bypassing
14
- * - Automatic audit logging
15
- * - Integration with existing RBAC system
16
- * - Page permission tracking
17
- * - Error handling and recovery
18
- *
19
- * @example
20
- * ```tsx
21
- * // Basic app setup with page permissions
22
- * <PagePermissionProvider strictMode={true} auditLog={true}>
23
- * <App />
24
- * </PagePermissionProvider>
25
- *
26
- * // With custom configuration
27
- * <PagePermissionProvider
28
- * strictMode={true}
29
- * auditLog={true}
30
- * onPageAccess={(pageName, operation, allowed) => {
31
- * console.log(`Page access: ${pageName} ${operation} - ${allowed ? 'allowed' : 'denied'}`);
32
- * }}
33
- * >
34
- * <App />
35
- * </PagePermissionProvider>
36
- * ```
37
- *
38
- * @security
39
- * - Enforces page-level permissions across the app
40
- * - Prevents apps from bypassing permission checks
41
- * - Automatic audit logging for all page access attempts
42
- * - Integration with existing RBAC system
43
- * - Page permission tracking and monitoring
44
- *
45
- * @performance
46
- * - Optimized with useMemo and useCallback
47
- * - Efficient context updates
48
- * - Minimal re-renders
49
- * - Cached permission checks
50
- *
51
- * @dependencies
52
- * - React 19+ - Context and hooks
53
- * - useUnifiedAuth - Authentication context
54
- * - RBAC types - Type definitions
55
- */
56
-
57
- import React, { createContext, useContext, useState, useCallback, useMemo, useEffect } from 'react';
58
- import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
59
- import { useResolvedScope } from '../hooks/useResolvedScope';
60
- import { UUID, Scope, Permission } from '../types';
61
- import { createLogger } from '../../utils/core/logger';
62
-
63
- const log = createLogger('PagePermissionProvider');
64
-
65
- export interface PagePermissionContextType {
66
- /** Check if user has permission for a page */
67
- hasPagePermission: (pageName: string, operation: string, pageId?: string, scope?: Scope) => boolean;
68
-
69
- /** Get all page permissions for current user */
70
- getPagePermissions: () => Record<string, string[]>;
71
-
72
- /** Check if page permission checking is enabled */
73
- isEnabled: boolean;
74
-
75
- /** Check if strict mode is enabled */
76
- isStrictMode: boolean;
77
-
78
- /** Check if audit logging is enabled */
79
- isAuditLogEnabled: boolean;
80
-
81
- /** Get page access history */
82
- getPageAccessHistory: () => PageAccessRecord[];
83
-
84
- /** Clear page access history */
85
- clearPageAccessHistory: () => void;
86
- }
87
-
88
- export interface PageAccessRecord {
89
- pageName: string;
90
- operation: string;
91
- userId: UUID;
92
- scope: Scope;
93
- allowed: boolean;
94
- timestamp: string;
95
- pageId?: string;
96
- }
97
-
98
- export interface PagePermissionProviderProps {
99
- /** Child components */
100
- children: React.ReactNode;
101
-
102
- /** Enable strict mode to prevent bypassing (default: true) */
103
- strictMode?: boolean;
104
-
105
- /** Enable audit logging (default: true) */
106
- auditLog?: boolean;
107
-
108
- /** Callback when page access is attempted */
109
- onPageAccess?: (pageName: string, operation: string, allowed: boolean, record: PageAccessRecord) => void;
110
-
111
- /** Callback when strict mode violation occurs */
112
- onStrictModeViolation?: (pageName: string, operation: string, record: PageAccessRecord) => void;
113
-
114
- /** Maximum number of access records to keep in history */
115
- maxHistorySize?: number;
116
- }
117
-
118
- const PagePermissionContext = createContext<PagePermissionContextType | null>(null);
119
-
120
- /**
121
- * PagePermissionProvider - Manages page-level permissions across the app
122
- *
123
- * This provider ensures that all pages are properly protected and provides
124
- * centralized page permission management with strict enforcement.
125
- *
126
- * @param props - Provider props
127
- * @returns React element with page permission context
128
- */
129
- export function PagePermissionProvider({
130
- children,
131
- strictMode = true,
132
- auditLog = true,
133
- onPageAccess,
134
- onStrictModeViolation,
135
- maxHistorySize = 1000
136
- }: PagePermissionProviderProps) {
137
- const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
138
- const [pageAccessHistory, setPageAccessHistory] = useState<PageAccessRecord[]>([]);
139
- const [isEnabled, setIsEnabled] = useState(true);
140
-
141
- // Use useResolvedScope to get proper scope (org derived from event if needed)
142
- const { resolvedScope } = useResolvedScope({
143
- supabase,
144
- selectedOrganisationId: selectedOrganisation?.id || null,
145
- selectedEventId: selectedEvent?.event_id || null
146
- });
147
-
148
- // Get current scope from resolved scope
149
- // For event-required apps: org is derived from event
150
- // For org-required apps: org comes from selectedOrganisation
151
- const currentScope = resolvedScope;
152
-
153
- // Check if user has permission for a page
154
- const hasPagePermission = useCallback((
155
- pageName: string,
156
- operation: string,
157
- pageId?: string,
158
- scope?: Scope
159
- ): boolean => {
160
- if (!isEnabled) return true;
161
- if (!user?.id) return false;
162
-
163
- const effectiveScope = scope || currentScope;
164
- if (!effectiveScope) return false;
165
-
166
- // Use the existing RBAC system to check permissions
167
- // This is a synchronous check for the context - actual permission checking
168
- // happens in the PagePermissionGuard component using useCan hook
169
- const permission = `${operation}:page.${pageName}` as Permission;
170
-
171
- // Return false by default (secure by default) - let individual PagePermissionGuard
172
- // components handle the actual permission checking asynchronously
173
- // This context is mainly for tracking and audit purposes
174
- return false;
175
- }, [isEnabled, user?.id, currentScope]);
176
-
177
- // Get all page permissions for current user
178
- const getPagePermissions = useCallback((): Record<string, string[]> => {
179
- if (!isEnabled || !user?.id) return {};
180
-
181
- // For now, return empty object - this will be enhanced with actual permission checking
182
- // when we integrate with the existing RBAC system
183
- return {};
184
- }, [isEnabled, user?.id]);
185
-
186
- // Get page access history
187
- const getPageAccessHistory = useCallback((): PageAccessRecord[] => {
188
- return [...pageAccessHistory];
189
- }, [pageAccessHistory]);
190
-
191
- // Clear page access history
192
- const clearPageAccessHistory = useCallback(() => {
193
- setPageAccessHistory([]);
194
- }, []);
195
-
196
- // Record page access attempt
197
- const recordPageAccess = useCallback((
198
- pageName: string,
199
- operation: string,
200
- allowed: boolean,
201
- pageId?: string,
202
- scope?: Scope
203
- ) => {
204
- if (!auditLog || !user?.id) return;
205
-
206
- const record: PageAccessRecord = {
207
- pageName,
208
- operation,
209
- userId: user.id,
210
- scope: scope || currentScope || { organisationId: '' },
211
- allowed,
212
- timestamp: new Date().toISOString(),
213
- pageId
214
- };
215
-
216
- setPageAccessHistory(prev => {
217
- const newHistory = [record, ...prev];
218
- return newHistory.slice(0, maxHistorySize);
219
- });
220
-
221
- if (onPageAccess) {
222
- onPageAccess(pageName, operation, allowed, record);
223
- }
224
-
225
- if (strictMode && !allowed && onStrictModeViolation) {
226
- onStrictModeViolation(pageName, operation, record);
227
- }
228
- }, [auditLog, user?.id, currentScope, maxHistorySize, onPageAccess, onStrictModeViolation, strictMode]);
229
-
230
- // Context value
231
- const contextValue = useMemo((): PagePermissionContextType => ({
232
- hasPagePermission,
233
- getPagePermissions,
234
- isEnabled,
235
- isStrictMode: strictMode,
236
- isAuditLogEnabled: auditLog,
237
- getPageAccessHistory,
238
- clearPageAccessHistory
239
- }), [
240
- hasPagePermission,
241
- getPagePermissions,
242
- isEnabled,
243
- strictMode,
244
- auditLog,
245
- getPageAccessHistory,
246
- clearPageAccessHistory
247
- ]);
248
-
249
- // Log strict mode violations
250
- useEffect(() => {
251
- if (strictMode && auditLog) {
252
- log.debug('Strict mode enabled - all page access attempts will be logged and enforced');
253
- }
254
- }, [strictMode, auditLog]);
255
-
256
- return (
257
- <PagePermissionContext.Provider value={contextValue}>
258
- {children}
259
- </PagePermissionContext.Provider>
260
- );
261
- }
262
-
263
- /**
264
- * Hook to use page permission context
265
- *
266
- * @returns Page permission context
267
- * @throws Error if used outside of PagePermissionProvider
268
- */
269
- export function usePagePermissions(): PagePermissionContextType {
270
- const context = useContext(PagePermissionContext);
271
-
272
- if (!context) {
273
- throw new Error('usePagePermissions must be used within a PagePermissionProvider');
274
- }
275
-
276
- return context;
277
- }
278
-
279
- export default PagePermissionProvider;
@@ -1,312 +0,0 @@
1
- /**
2
- * @file Permission Enforcer Component
3
- * @package @jmruthers/pace-core
4
- * @module RBAC/Components/PermissionEnforcer
5
- * @since 2.0.0
6
- *
7
- * A component that enforces permissions and prevents apps from bypassing permission checks.
8
- * This is a critical security component that provides centralized permission enforcement.
9
- *
10
- * Features:
11
- * - Centralized permission enforcement
12
- * - Strict mode to prevent bypassing
13
- * - Automatic audit logging
14
- * - Integration with existing RBAC system
15
- * - Multiple permission checking
16
- * - Clear error messages for unauthorized access
17
- *
18
- * @example
19
- * ```tsx
20
- * // Basic permission enforcement
21
- * <PermissionEnforcer
22
- * permissions={['read:events', 'update:events']}
23
- * operation="event-management"
24
- * fallback={<AccessDeniedPage />}
25
- * >
26
- * <EventManagementPage />
27
- * </PermissionEnforcer>
28
- *
29
- * // Strict mode (prevents bypassing)
30
- * <PermissionEnforcer
31
- * permissions={['admin:system']}
32
- * operation="system-administration"
33
- * strictMode={true}
34
- * fallback={<AccessDeniedPage />}
35
- * >
36
- * <SystemAdminPage />
37
- * </PermissionEnforcer>
38
- *
39
- * // With custom fallback
40
- * <PermissionEnforcer
41
- * permissions={['update:settings']}
42
- * operation="settings-update"
43
- * fallback={<div>You don't have permission to update settings</div>}
44
- * >
45
- * <SettingsUpdatePage />
46
- * </PermissionEnforcer>
47
- * ```
48
- *
49
- * @security
50
- * - Enforces permissions for all operations
51
- * - Prevents apps from bypassing permission checks
52
- * - Automatic audit logging for all permission checks
53
- * - Integration with existing RBAC system
54
- * - Clear error messages for unauthorized access
55
- *
56
- * @performance
57
- * - Optimized with useMemo and useCallback
58
- * - Cached permission checks
59
- * - Minimal re-renders
60
- * - Efficient error handling
61
- *
62
- * @dependencies
63
- * - React 19+ - Component framework
64
- * - useCan hook - Permission checking
65
- * - useUnifiedAuth - Authentication context
66
- * - RBAC types - Type definitions
67
- */
68
-
69
- import React, { useMemo, useCallback, useEffect, useState, useRef } from 'react';
70
- import { useMultiplePermissions } from '../hooks/usePermissions';
71
- import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
72
- import { useResolvedScope } from '../hooks/useResolvedScope';
73
- import { UUID, Permission, Scope } from '../types';
74
- import { getRBACLogger } from '../config';
75
- import { createLogger } from '../../utils/core/logger';
76
-
77
- const log = createLogger('PermissionEnforcer');
78
-
79
- export interface PermissionEnforcerProps {
80
- /** Permissions required for access */
81
- permissions: Permission[];
82
-
83
- /** Operation being performed */
84
- operation: string;
85
-
86
- /** Content to render when user has permission */
87
- children: React.ReactNode;
88
-
89
- /** Content to render when user lacks permission */
90
- fallback?: React.ReactNode;
91
-
92
- /** Enable strict mode to prevent bypassing (default: true) */
93
- strictMode?: boolean;
94
-
95
- /** Force audit logging for this operation (default: true) */
96
- auditLog?: boolean;
97
-
98
- /** Custom scope for permission checking */
99
- scope?: Scope;
100
-
101
- /** Callback when access is denied */
102
- onDenied?: (permissions: Permission[], operation: string) => void;
103
-
104
- /** Loading state content */
105
- loading?: React.ReactNode;
106
-
107
- /** Require all permissions (AND) or any permission (OR) */
108
- requireAll?: boolean;
109
- }
110
-
111
- /**
112
- * PermissionEnforcer - Enforces permissions for operations
113
- *
114
- * This component ensures that users can only perform operations they have permission for.
115
- * It integrates with the existing RBAC system and provides strict enforcement to
116
- * prevent apps from bypassing permission checks.
117
- *
118
- * @param props - Component props
119
- * @returns React element with permission enforcement
120
- */
121
- export function PermissionEnforcer({
122
- permissions,
123
- operation,
124
- children,
125
- fallback = <DefaultAccessDenied />,
126
- strictMode = true,
127
- auditLog = true,
128
- scope,
129
- onDenied,
130
- loading = <DefaultLoading />,
131
- requireAll = true
132
- }: PermissionEnforcerProps) {
133
- const { user, selectedOrganisation, selectedEvent, supabase } = useUnifiedAuth();
134
- const [hasChecked, setHasChecked] = useState(false);
135
-
136
- // Use useResolvedScope hook for consistent scope resolution
137
- // For event-required apps: selectedOrganisation is null, org derived from event
138
- // For org-required apps: selectedOrganisation is available, event optional
139
- const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
140
- supabase,
141
- selectedOrganisationId: selectedOrganisation?.id || null,
142
- selectedEventId: selectedEvent?.event_id || null
143
- });
144
-
145
- // Use provided scope if available, otherwise use resolved scope
146
- // Extract primitive values to ensure stable reference comparison
147
- // This prevents useMultiplePermissions from re-checking when scope object reference changes but values are the same
148
- const scopeToUse = scope || resolvedScope;
149
- const scopeOrgId = scopeToUse?.organisationId || '';
150
- const scopeEventId = scopeToUse?.eventId || undefined;
151
- const scopeAppId = scopeToUse?.appId || undefined;
152
-
153
- // Memoize effectiveScope using primitive values to ensure stable reference
154
- // Always create a new scope object from primitive values to prevent reference changes
155
- const effectiveScope = useMemo(() => {
156
- const newScope: Scope = {};
157
- if (scopeOrgId) {
158
- newScope.organisationId = scopeOrgId;
159
- }
160
- if (scopeEventId) {
161
- newScope.eventId = scopeEventId;
162
- }
163
- if (scopeAppId) {
164
- newScope.appId = scopeAppId;
165
- }
166
- return newScope;
167
- }, [scopeOrgId, scopeEventId, scopeAppId]);
168
- const checkError = scopeError;
169
-
170
- // Check all permissions using useMultiplePermissions hook
171
- const { results: permissionResults, isLoading: permissionsLoading, error: permissionsError } = useMultiplePermissions(
172
- user?.id || '',
173
- effectiveScope || { eventId: selectedEvent?.event_id || undefined },
174
- permissions,
175
- true // Use cache
176
- );
177
-
178
- const isLoading = scopeLoading || permissionsLoading;
179
- const error = checkError || permissionsError;
180
-
181
- // Determine if user has required permissions based on requireAll prop
182
- const hasRequiredPermissions = useMemo((): boolean => {
183
- if (permissions.length === 0) return true;
184
-
185
- // If permissionResults is not yet available or empty, deny access
186
- if (!permissionResults || Object.keys(permissionResults).length === 0) {
187
- return false;
188
- }
189
-
190
- if (requireAll) {
191
- // User must have ALL permissions
192
- return Object.values(permissionResults).every(result => result === true);
193
- } else {
194
- // User must have ANY permission (default behavior)
195
- return Object.values(permissionResults).some(result => result === true);
196
- }
197
- }, [permissions, permissionResults, requireAll]);
198
-
199
- // Handle permission check completion
200
- useEffect(() => {
201
- if (!isLoading && !error) {
202
- setHasChecked(true);
203
-
204
- if (!hasRequiredPermissions && onDenied) {
205
- onDenied(permissions, operation);
206
- }
207
- } else if (error) {
208
- setHasChecked(true);
209
- }
210
- }, [hasRequiredPermissions, isLoading, error, permissions, operation, onDenied]);
211
-
212
- // Log permission check attempt for audit
213
- // Only log once per unique permission check result to prevent spam
214
- // Use the scope primitive values already extracted above
215
- const permissionsKey = permissions.join(',');
216
-
217
- const lastLoggedKeyRef = useRef<string | null>(null);
218
- useEffect(() => {
219
- if (auditLog && hasChecked && !isLoading) {
220
- // Create a stable key based on the permission check result values (not object references)
221
- const logKey = `${operation}-${user?.id}-${permissionsKey}-${hasRequiredPermissions}-${scopeOrgId}-${scopeEventId}-${scopeAppId}`;
222
-
223
- // Only log if this is a new result (different from last logged)
224
- if (lastLoggedKeyRef.current !== logKey) {
225
- lastLoggedKeyRef.current = logKey;
226
- log.debug('Permission check attempt:', {
227
- permissions,
228
- operation,
229
- userId: user?.id,
230
- scope: effectiveScope,
231
- allowed: hasRequiredPermissions,
232
- requireAll,
233
- timestamp: new Date().toISOString()
234
- });
235
- }
236
- }
237
- }, [auditLog, hasChecked, isLoading, permissionsKey, operation, user?.id, scopeOrgId, scopeEventId, scopeAppId, hasRequiredPermissions]);
238
-
239
- // Handle strict mode violations
240
- useEffect(() => {
241
- if (strictMode && hasChecked && !isLoading && !hasRequiredPermissions) {
242
- const logger = getRBACLogger();
243
- logger.error(`STRICT MODE VIOLATION: User attempted to perform operation without permission`, {
244
- permissions,
245
- operation,
246
- userId: user?.id,
247
- scope: effectiveScope,
248
- requireAll,
249
- timestamp: new Date().toISOString()
250
- });
251
- }
252
- }, [strictMode, hasChecked, isLoading, hasRequiredPermissions, permissions, operation, user?.id, effectiveScope, requireAll]);
253
-
254
- // Show loading state
255
- if (isLoading || !hasChecked) {
256
- return <>{loading}</>;
257
- }
258
-
259
- // Show error state
260
- if (checkError) {
261
- const logger = getRBACLogger();
262
- logger.error(`Permission check failed for operation ${operation}:`, checkError);
263
- return <>{fallback}</>;
264
- }
265
-
266
- // Show access denied
267
- if (!hasRequiredPermissions) {
268
- return <>{fallback}</>;
269
- }
270
-
271
- // Show protected content
272
- return <>{children}</>;
273
- }
274
-
275
- /**
276
- * Default access denied component
277
- */
278
- function DefaultAccessDenied() {
279
- return (
280
- <div className="flex flex-col items-center justify-center min-h-[200px] p-8 text-center">
281
- <div className="mb-4">
282
- <svg className="w-16 h-16 text-acc-500 mx-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24">
283
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M12 9v2m0 4h.01m-6.938 4h13.856c1.54 0 2.502-1.667 1.732-2.5L13.732 4c-.77-.833-1.964-.833-2.732 0L3.732 16.5c-.77.833.192 2.5 1.732 2.5z" />
284
- </svg>
285
- </div>
286
- <h2 className="text-xl font-semibold text-sec-900 mb-2">Access Denied</h2>
287
- <p className="text-sec-600 mb-4">You don't have permission to perform this operation.</p>
288
- <button
289
- onClick={() => window.history.back()}
290
- className="px-4 py-2 bg-main-600 text-main-50 rounded-md hover:bg-main-700 transition-colors"
291
- >
292
- Go Back
293
- </button>
294
- </div>
295
- );
296
- }
297
-
298
- /**
299
- * Default loading component
300
- */
301
- function DefaultLoading() {
302
- return (
303
- <div className="flex items-center justify-center min-h-[200px] p-8">
304
- <div className="flex items-center space-x-2">
305
- <div className="animate-spin rounded-full size-8 border-b-2 border-main-600"></div>
306
- <span className="text-sec-600">Checking permissions...</span>
307
- </div>
308
- </div>
309
- );
310
- }
311
-
312
- export default PermissionEnforcer;