@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
@@ -40,12 +40,15 @@
40
40
  * - Missing user context results in all permissions being denied
41
41
  */
42
42
 
43
- import { useMemo } from 'react';
43
+ import { useMemo, useState, useEffect, useRef } from 'react';
44
44
  import { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';
45
45
  import { useOrganisations } from '../../hooks/useOrganisations';
46
46
  import { useEvents } from '../../hooks/useEvents';
47
+ import type { Event } from '../../types/event';
47
48
  import { useResolvedScope } from './useResolvedScope';
48
49
  import { useCan } from './usePermissions';
50
+ import { isSuperAdmin } from '../api';
51
+ import { createLogger } from '../../utils/core/logger';
49
52
  import type { Scope, Permission } from '../types';
50
53
 
51
54
  export interface UseResourcePermissionsOptions {
@@ -140,15 +143,80 @@ export function useResourcePermissions(
140
143
  options: UseResourcePermissionsOptions = {}
141
144
  ): ResourcePermissions {
142
145
  const { enableRead = false, requireScope = true } = options;
146
+ const logger = createLogger('ResourcePermissions');
143
147
 
144
148
  // Get user and supabase client from UnifiedAuth
145
149
  const { user, supabase } = useUnifiedAuth();
150
+
151
+ // Super admin status - check if user has super admin privileges
152
+ // Super admins bypass all permission checks (similar to useDataTablePermissions)
153
+ // PERFORMANCE OPTIMIZATION: Check super admin once and share with all useCan hooks to avoid duplicate queries
154
+ // Use null to indicate "not checked yet" vs false which means "checked and not super admin"
155
+ const [isSuperAdminUser, setIsSuperAdminUser] = useState<boolean | null>(null);
156
+ const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState<boolean>(() => !!user?.id);
157
+ const lastCheckedUserIdRef = useRef<string | null>(null);
158
+ const isCheckingRef = useRef<boolean>(false);
159
+
160
+ useEffect(() => {
161
+ // Skip if already checked for this user ID
162
+ if (lastCheckedUserIdRef.current === user?.id && isSuperAdminUser !== null) {
163
+ return;
164
+ }
165
+
166
+ // Skip if already checking
167
+ if (isCheckingRef.current) {
168
+ return;
169
+ }
170
+
171
+ const checkSuperAdminStatus = async () => {
172
+ if (!user?.id) {
173
+ setIsSuperAdminUser(false); // No user = not super admin
174
+ setIsCheckingSuperAdmin(false);
175
+ lastCheckedUserIdRef.current = null;
176
+ return;
177
+ }
178
+
179
+ // Mark as checking and track user ID
180
+ isCheckingRef.current = true;
181
+ lastCheckedUserIdRef.current = user.id;
182
+
183
+ const startTime = Date.now();
184
+ setIsCheckingSuperAdmin(true);
185
+
186
+ // Add timeout to prevent infinite hanging
187
+ const timeoutId = setTimeout(() => {
188
+ logger.warn('useResourcePermissions', 'Super admin check taking longer than 5 seconds', {
189
+ userId: user?.id,
190
+ elapsedMs: Date.now() - startTime,
191
+ });
192
+ }, 5000);
193
+
194
+ try {
195
+ const superAdminStatus = await isSuperAdmin(user.id);
196
+ setIsSuperAdminUser(superAdminStatus);
197
+ } catch (error) {
198
+ const elapsed = Date.now() - startTime;
199
+ logger.error('useResourcePermissions', 'Error checking super admin status', {
200
+ userId: user?.id,
201
+ error,
202
+ elapsedMs: elapsed,
203
+ });
204
+ setIsSuperAdminUser(false); // Error = assume not super admin for security
205
+ } finally {
206
+ clearTimeout(timeoutId);
207
+ setIsCheckingSuperAdmin(false);
208
+ isCheckingRef.current = false;
209
+ }
210
+ };
211
+
212
+ checkSuperAdminStatus();
213
+ }, [user?.id, logger]);
146
214
 
147
215
  // Get selected organisation
148
216
  const { selectedOrganisation } = useOrganisations();
149
217
 
150
218
  // Get selected event (optional - wrap in try/catch)
151
- let selectedEvent: { event_id: string } | null = null;
219
+ let selectedEvent: Event | null = null;
152
220
  try {
153
221
  const eventsContext = useEvents();
154
222
  selectedEvent = eventsContext.selectedEvent;
@@ -161,7 +229,8 @@ export function useResourcePermissions(
161
229
  const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({
162
230
  supabase,
163
231
  selectedOrganisationId: selectedOrganisation?.id || null,
164
- selectedEventId: selectedEvent?.event_id || null
232
+ selectedEventId: selectedEvent?.event_id || null,
233
+ selectedEventOrganisationId: selectedEvent?.organisation_id || null
165
234
  });
166
235
 
167
236
  // CRITICAL FIX: Only use resolvedScope when it's available (not during loading)
@@ -192,8 +261,9 @@ export function useResourcePermissions(
192
261
  const readPermission = isPagePermission ? `read:page.${resource}` : `read:${resource}`;
193
262
 
194
263
  // Permission checks for create, update, delete
195
- // Pass null for super admin status (not checked yet - hook will check if needed)
196
- // PERFORMANCE: These hooks will each check super admin separately - could be optimized in future
264
+ // PERFORMANCE OPTIMIZATION: Pass precomputed super admin status to avoid duplicate checks
265
+ // Each useCan hook would normally check super admin separately (4+ queries), but we check once here
266
+ // and share the result. Pass null if not checked yet (hooks will check), false/true if checked.
197
267
  // CRITICAL: useCan will wait for appId when pageId is provided (it checks needsAppIdForPageName)
198
268
  // But we must ensure permission strings are correct before calling useCan
199
269
  const { can: canCreateResult, isLoading: createLoading, error: createError } = useCan(
@@ -202,7 +272,7 @@ export function useResourcePermissions(
202
272
  createPermission as Permission,
203
273
  pageId, // Pass resource name as pageId when appId is available to enable page permission checks
204
274
  true, // useCache
205
- null, // precomputedSuperAdmin - not checked yet
275
+ isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
206
276
  undefined // appName
207
277
  );
208
278
 
@@ -212,7 +282,7 @@ export function useResourcePermissions(
212
282
  updatePermission as Permission,
213
283
  pageId, // Pass resource name as pageId when appId is available to enable page permission checks
214
284
  true, // useCache
215
- null, // precomputedSuperAdmin - not checked yet
285
+ isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
216
286
  undefined // appName
217
287
  );
218
288
 
@@ -222,7 +292,7 @@ export function useResourcePermissions(
222
292
  deletePermission as Permission,
223
293
  pageId, // Pass resource name as pageId when appId is available to enable page permission checks
224
294
  true, // useCache
225
- null, // precomputedSuperAdmin - not checked yet
295
+ isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
226
296
  undefined // appName
227
297
  );
228
298
 
@@ -233,7 +303,7 @@ export function useResourcePermissions(
233
303
  readPermission as Permission,
234
304
  pageId, // Pass resource name as pageId when appId is available to enable page permission checks
235
305
  true, // useCache
236
- null, // precomputedSuperAdmin - not checked yet
306
+ isSuperAdminUser, // precomputedSuperAdmin - null if checking, false/true if checked
237
307
  undefined // appName
238
308
  );
239
309
 
@@ -241,11 +311,14 @@ export function useResourcePermissions(
241
311
  // CRITICAL: When requireScope is true, we must wait for scope resolution to complete
242
312
  // so we can determine the correct permission format (page vs resource permissions)
243
313
  // This prevents using wrong permission format (delete:planning instead of delete:page.planning)
314
+ // Also wait for super admin check to complete to ensure accurate permission results
244
315
  const isLoading = useMemo(() => {
245
316
  // If scope resolution is required, wait for it to complete
246
317
  const waitingForScope = requireScope && scopeLoading;
247
- return waitingForScope || createLoading || updateLoading || deleteLoading || (enableRead && readLoading);
248
- }, [scopeLoading, requireScope, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
318
+ // Wait for super admin check to complete (null means still checking)
319
+ const waitingForSuperAdmin = isSuperAdminUser === null && isCheckingSuperAdmin;
320
+ return waitingForScope || waitingForSuperAdmin || createLoading || updateLoading || deleteLoading || (enableRead && readLoading);
321
+ }, [scopeLoading, requireScope, isSuperAdminUser, isCheckingSuperAdmin, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);
249
322
 
250
323
  // Aggregate errors - prefer scope error, then any permission error
251
324
  const error = useMemo(() => {
@@ -260,45 +333,63 @@ export function useResourcePermissions(
260
333
  // Return wrapper functions that take resource name and return permission result
261
334
  // Note: The resource parameter in the function is for consistency with the API,
262
335
  // but we're checking permissions for the resource passed to the hook
263
- return useMemo(() => ({
264
- canCreate: (res: string) => {
265
- // For now, we only check the resource passed to the hook
266
- // Future enhancement could support checking different resources
267
- if (res !== resource) {
268
- return false;
269
- }
270
- return canCreateResult; // canCreateResult is already the boolean 'can' value from useCan
271
- },
272
- canUpdate: (res: string) => {
273
- if (res !== resource) {
274
- return false;
275
- }
276
- return canUpdateResult; // canUpdateResult is already the boolean 'can' value from useCan
277
- },
278
- canDelete: (res: string) => {
279
- if (res !== resource) {
280
- return false;
281
- }
282
- return canDeleteResult; // canDeleteResult is already the boolean 'can' value from useCan
283
- },
284
- canRead: (res: string) => {
285
- if (!enableRead) {
286
- return true; // If read checking is disabled, allow read
287
- }
288
- if (res !== resource) {
289
- return false;
336
+ // CRITICAL FIX: When isSuperAdminUser is true, immediately grant all permissions without waiting
337
+ // for useCan results. This ensures super admins can use resource operations immediately.
338
+ return useMemo(() => {
339
+ // Helper to create a permission result that bypasses for super admins
340
+ const createSuperAdminAwarePermission = (result: boolean) => {
341
+ // CRITICAL: If super admin is confirmed, immediately grant permission
342
+ // Don't wait for useCan results - super admins bypass all checks
343
+ if (isSuperAdminUser === true) {
344
+ return true;
290
345
  }
291
- return canReadResult; // canReadResult is already the boolean 'can' value from useCan
292
- },
293
- scope,
294
- isLoading,
295
- error
296
- }), [
346
+
347
+ // For non-super-admins or while checking, use normal permission results
348
+ return result;
349
+ };
350
+
351
+ return {
352
+ canCreate: (res: string) => {
353
+ // For now, we only check the resource passed to the hook
354
+ // Future enhancement could support checking different resources
355
+ if (res !== resource) {
356
+ return false;
357
+ }
358
+ return createSuperAdminAwarePermission(canCreateResult);
359
+ },
360
+ canUpdate: (res: string) => {
361
+ if (res !== resource) {
362
+ return false;
363
+ }
364
+ return createSuperAdminAwarePermission(canUpdateResult);
365
+ },
366
+ canDelete: (res: string) => {
367
+ if (res !== resource) {
368
+ return false;
369
+ }
370
+ return createSuperAdminAwarePermission(canDeleteResult);
371
+ },
372
+ canRead: (res: string) => {
373
+ if (!enableRead) {
374
+ return true; // If read checking is disabled, allow read
375
+ }
376
+ if (res !== resource) {
377
+ return false;
378
+ }
379
+ return createSuperAdminAwarePermission(canReadResult);
380
+ },
381
+ scope,
382
+ isLoading: isCheckingSuperAdmin || isLoading,
383
+ error
384
+ };
385
+ }, [
297
386
  resource,
298
- canCreateResult, // This is already the boolean 'can' value
299
- canUpdateResult, // This is already the boolean 'can' value
300
- canDeleteResult, // This is already the boolean 'can' value
301
- canReadResult, // This is already the boolean 'can' value
387
+ isSuperAdminUser,
388
+ isCheckingSuperAdmin,
389
+ canCreateResult,
390
+ canUpdateResult,
391
+ canDeleteResult,
392
+ canReadResult,
302
393
  enableRead,
303
394
  scope,
304
395
  isLoading,
@@ -8,7 +8,7 @@
8
8
  * Tests focus on behavior: role granting, revoking, loading states, and error handling.
9
9
  */
10
10
 
11
- import { renderHook, waitFor } from '@testing-library/react';
11
+ import { renderHook, waitFor, act } from '@testing-library/react';
12
12
  import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
13
13
  import { useRoleManagement } from './useRoleManagement';
14
14
  import type { SupabaseClient } from '@supabase/supabase-js';
@@ -105,7 +105,7 @@ describe('useRoleManagement Hook', () => {
105
105
  describe('revokeEventAppRole', () => {
106
106
  it('revokes role successfully', async () => {
107
107
  (mockSupabase.rpc as any).mockResolvedValue({
108
- data: true,
108
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
109
109
  error: null,
110
110
  });
111
111
 
@@ -117,19 +117,18 @@ describe('useRoleManagement Hook', () => {
117
117
  expect(revokeResult.message).toBe('Role revoked successfully');
118
118
  expect(revokeResult.error).toBeUndefined();
119
119
  expect(result.current.error).toBeNull();
120
- expect(mockSupabase.rpc).toHaveBeenCalledWith('revoke_event_app_role', {
120
+ expect(mockSupabase.rpc).toHaveBeenCalledWith('rbac_role_revoke', {
121
121
  p_user_id: 'user-456',
122
- p_organisation_id: 'org-123',
123
- p_event_id: 'event-123',
124
- p_app_id: 'app-123',
125
- p_role: 'viewer',
122
+ p_role_type: 'event_app',
123
+ p_role_name: 'viewer',
124
+ p_context_id: 'event-123:app-123',
126
125
  p_revoked_by: 'user-123',
127
126
  });
128
127
  });
129
128
 
130
129
  it('handles case when role not found', async () => {
131
130
  (mockSupabase.rpc as any).mockResolvedValue({
132
- data: false,
131
+ data: [{ success: false, message: 'No matching role found', revoked_count: 0, error_code: 'ROLE_NOT_FOUND' }],
133
132
  error: null,
134
133
  });
135
134
 
@@ -138,13 +137,55 @@ describe('useRoleManagement Hook', () => {
138
137
  const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
139
138
 
140
139
  expect(revokeResult.success).toBe(false);
141
- expect(revokeResult.message).toBe('No role found to revoke');
140
+ expect(revokeResult.message).toBe('No matching role found');
142
141
  expect(revokeResult.error).toBe('No matching role found');
143
142
  });
144
143
 
144
+ it('handles empty data response', async () => {
145
+ (mockSupabase.rpc as any).mockResolvedValue({
146
+ data: [],
147
+ error: null,
148
+ });
149
+
150
+ const { result } = renderHook(() => useRoleManagement());
151
+
152
+ const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
153
+
154
+ expect(revokeResult.success).toBe(false);
155
+ expect(revokeResult.error).toBe('No response from database - role revocation may have failed');
156
+ });
157
+
158
+ it('handles null data response', async () => {
159
+ (mockSupabase.rpc as any).mockResolvedValue({
160
+ data: null,
161
+ error: null,
162
+ });
163
+
164
+ const { result } = renderHook(() => useRoleManagement());
165
+
166
+ const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
167
+
168
+ expect(revokeResult.success).toBe(false);
169
+ expect(revokeResult.error).toBe('No response from database - role revocation may have failed');
170
+ });
171
+
172
+ it('handles result with success false but no message', async () => {
173
+ (mockSupabase.rpc as any).mockResolvedValue({
174
+ data: [{ success: false, message: null, revoked_count: 0, error_code: 'ROLE_NOT_FOUND' }],
175
+ error: null,
176
+ });
177
+
178
+ const { result } = renderHook(() => useRoleManagement());
179
+
180
+ const revokeResult = await result.current.revokeEventAppRole(mockRoleParams);
181
+
182
+ expect(revokeResult.success).toBe(false);
183
+ expect(revokeResult.error).toBe('ROLE_NOT_FOUND');
184
+ });
185
+
145
186
  it('uses provided revoked_by parameter', async () => {
146
187
  (mockSupabase.rpc as any).mockResolvedValue({
147
- data: true,
188
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
148
189
  error: null,
149
190
  });
150
191
 
@@ -156,7 +197,7 @@ describe('useRoleManagement Hook', () => {
156
197
  });
157
198
 
158
199
  expect(mockSupabase.rpc).toHaveBeenCalledWith(
159
- 'revoke_event_app_role',
200
+ 'rbac_role_revoke',
160
201
  expect.objectContaining({
161
202
  p_revoked_by: 'admin-789',
162
203
  })
@@ -165,7 +206,7 @@ describe('useRoleManagement Hook', () => {
165
206
 
166
207
  it('uses user ID as revoked_by when not provided', async () => {
167
208
  (mockSupabase.rpc as any).mockResolvedValue({
168
- data: true,
209
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
169
210
  error: null,
170
211
  });
171
212
 
@@ -174,7 +215,7 @@ describe('useRoleManagement Hook', () => {
174
215
  await result.current.revokeEventAppRole(mockRoleParams);
175
216
 
176
217
  expect(mockSupabase.rpc).toHaveBeenCalledWith(
177
- 'revoke_event_app_role',
218
+ 'rbac_role_revoke',
178
219
  expect.objectContaining({
179
220
  p_revoked_by: 'user-123',
180
221
  })
@@ -262,7 +303,7 @@ describe('useRoleManagement Hook', () => {
262
303
  );
263
304
 
264
305
  resolvePromise!({
265
- data: true,
306
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
266
307
  error: null,
267
308
  });
268
309
 
@@ -461,14 +502,16 @@ describe('useRoleManagement Hook', () => {
461
502
 
462
503
  const { result } = renderHook(() => useRoleManagement());
463
504
 
505
+ // Call grantEventAppRole - loading state is set synchronously, but React state updates are async
464
506
  const grantPromise = result.current.grantEventAppRole(mockRoleParams);
465
507
 
466
- // Loading state is set synchronously, but React state updates are async
508
+ // Wait for React to process the state update (setIsLoading(true))
509
+ // Increased timeout to allow React to batch and process state updates
467
510
  await waitFor(
468
511
  () => {
469
512
  expect(result.current.isLoading).toBe(true);
470
513
  },
471
- { timeout: 100 }
514
+ { timeout: 1000 }
472
515
  );
473
516
 
474
517
  resolvePromise!({
@@ -797,9 +840,9 @@ describe('useRoleManagement Hook', () => {
797
840
  });
798
841
 
799
842
  expect(mockSupabase.rpc).toHaveBeenCalledWith(
800
- 'revoke_event_app_role',
843
+ 'rbac_role_revoke',
801
844
  expect.objectContaining({
802
- p_role: role,
845
+ p_role_name: role,
803
846
  })
804
847
  );
805
848
  }
@@ -825,7 +868,7 @@ describe('useRoleManagement Hook', () => {
825
868
 
826
869
  // Second call succeeds
827
870
  (mockSupabase.rpc as any).mockResolvedValueOnce({
828
- data: true,
871
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
829
872
  error: null,
830
873
  });
831
874
 
@@ -850,7 +893,7 @@ describe('useRoleManagement Hook', () => {
850
893
 
851
894
  // Second call succeeds
852
895
  (mockSupabase.rpc as any).mockResolvedValueOnce({
853
- data: true,
896
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
854
897
  error: null,
855
898
  });
856
899
 
@@ -864,7 +907,7 @@ describe('useRoleManagement Hook', () => {
864
907
  describe('Concurrent Operations', () => {
865
908
  it('handles concurrent role operations', async () => {
866
909
  (mockSupabase.rpc as any).mockResolvedValue({
867
- data: true,
910
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
868
911
  error: null,
869
912
  });
870
913
 
@@ -885,7 +928,7 @@ describe('useRoleManagement Hook', () => {
885
928
 
886
929
  it('handles rapid sequential operations', async () => {
887
930
  (mockSupabase.rpc as any).mockResolvedValue({
888
- data: true,
931
+ data: [{ success: true, message: 'Role revoked successfully', revoked_count: 1 }],
889
932
  error: null,
890
933
  });
891
934