@jmruthers/pace-core 0.5.189 → 0.5.191

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 (438) hide show
  1. package/core-usage-manifest.json +0 -4
  2. package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
  3. package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
  4. package/dist/{DataTable-GUFUNZ3N.js → DataTable-WKRZD47S.js} +8 -8
  5. package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +84 -25
  6. package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
  7. package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-FTSG5XH7.js} +4 -2
  8. package/dist/{api-YP7XD5L6.js → api-IHKALJZD.js} +4 -2
  9. package/dist/{chunk-VGZZXKBR.js → chunk-6LTQQAT6.js} +351 -157
  10. package/dist/chunk-6LTQQAT6.js.map +1 -0
  11. package/dist/{chunk-MX64ZF6I.js → chunk-6TQDD426.js} +15 -15
  12. package/dist/chunk-6TQDD426.js.map +1 -0
  13. package/dist/{chunk-YHCN776L.js → chunk-G37KK66H.js} +2 -75
  14. package/dist/chunk-G37KK66H.js.map +1 -0
  15. package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
  16. package/dist/chunk-HW3OVDUF.js.map +1 -0
  17. package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
  18. package/dist/chunk-I7PSE6JW.js.map +1 -0
  19. package/dist/{chunk-IM4QE42D.js → chunk-LOMZXPSN.js} +141 -326
  20. package/dist/chunk-LOMZXPSN.js.map +1 -0
  21. package/dist/chunk-OETXORNB.js +614 -0
  22. package/dist/chunk-OETXORNB.js.map +1 -0
  23. package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
  24. package/dist/{chunk-HEHYGYOX.js → chunk-ROXMHMY2.js} +403 -46
  25. package/dist/chunk-ROXMHMY2.js.map +1 -0
  26. package/dist/{chunk-2UUZZJFT.js → chunk-ULHIJK66.js} +228 -177
  27. package/dist/{chunk-2UUZZJFT.js.map → chunk-ULHIJK66.js.map} +1 -1
  28. package/dist/{chunk-YGPFYGA6.js → chunk-VKB2CO4Z.js} +838 -503
  29. package/dist/chunk-VKB2CO4Z.js.map +1 -0
  30. package/dist/{chunk-3GOZZZYH.js → chunk-VRGWKHDB.js} +238 -301
  31. package/dist/chunk-VRGWKHDB.js.map +1 -0
  32. package/dist/{chunk-UCQSRW7Z.js → chunk-XNYQOL3Z.js} +431 -384
  33. package/dist/chunk-XNYQOL3Z.js.map +1 -0
  34. package/dist/{chunk-DDM4CCYT.js → chunk-XYXSXPUK.js} +79 -59
  35. package/dist/chunk-XYXSXPUK.js.map +1 -0
  36. package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
  37. package/dist/chunk-ZSAAAMVR.js.map +1 -0
  38. package/dist/components.d.ts +5 -6
  39. package/dist/components.js +19 -19
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
  42. package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
  43. package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
  44. package/dist/hooks.d.ts +20 -15
  45. package/dist/hooks.js +14 -8
  46. package/dist/hooks.js.map +1 -1
  47. package/dist/index.d.ts +17 -15
  48. package/dist/index.js +86 -81
  49. package/dist/index.js.map +1 -1
  50. package/dist/providers.d.ts +3 -3
  51. package/dist/providers.js +3 -1
  52. package/dist/rbac/index.d.ts +77 -13
  53. package/dist/rbac/index.js +12 -9
  54. package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
  55. package/dist/types.d.ts +3 -3
  56. package/dist/types.js +1 -1
  57. package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +17 -10
  58. package/dist/utils.d.ts +8 -8
  59. package/dist/utils.js +16 -16
  60. package/docs/README.md +2 -2
  61. package/docs/api/classes/ColumnFactory.md +1 -1
  62. package/docs/api/classes/ErrorBoundary.md +1 -1
  63. package/docs/api/classes/InvalidScopeError.md +2 -2
  64. package/docs/api/classes/Logger.md +1 -1
  65. package/docs/api/classes/MissingUserContextError.md +2 -2
  66. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  67. package/docs/api/classes/PermissionDeniedError.md +1 -1
  68. package/docs/api/classes/RBACAuditManager.md +2 -2
  69. package/docs/api/classes/RBACCache.md +1 -1
  70. package/docs/api/classes/RBACEngine.md +5 -5
  71. package/docs/api/classes/RBACError.md +1 -1
  72. package/docs/api/classes/RBACNotInitializedError.md +2 -2
  73. package/docs/api/classes/SecureSupabaseClient.md +25 -20
  74. package/docs/api/classes/StorageUtils.md +7 -4
  75. package/docs/api/enums/FileCategory.md +1 -1
  76. package/docs/api/enums/LogLevel.md +1 -1
  77. package/docs/api/enums/RBACErrorCode.md +1 -1
  78. package/docs/api/enums/RPCFunction.md +1 -1
  79. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  80. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +1 -1
  82. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  83. package/docs/api/interfaces/AvatarProps.md +1 -1
  84. package/docs/api/interfaces/BadgeProps.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CalendarProps.md +20 -6
  87. package/docs/api/interfaces/CardProps.md +1 -1
  88. package/docs/api/interfaces/ColorPalette.md +1 -1
  89. package/docs/api/interfaces/ColorShade.md +1 -1
  90. package/docs/api/interfaces/ComplianceResult.md +1 -1
  91. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  92. package/docs/api/interfaces/DataRecord.md +1 -1
  93. package/docs/api/interfaces/DataTableAction.md +1 -1
  94. package/docs/api/interfaces/DataTableColumn.md +1 -1
  95. package/docs/api/interfaces/DataTableProps.md +1 -1
  96. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  97. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  98. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  99. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  100. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  101. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  102. package/docs/api/interfaces/ExportColumn.md +1 -1
  103. package/docs/api/interfaces/ExportOptions.md +1 -1
  104. package/docs/api/interfaces/FileDisplayProps.md +62 -16
  105. package/docs/api/interfaces/FileMetadata.md +1 -1
  106. package/docs/api/interfaces/FileReference.md +2 -2
  107. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  108. package/docs/api/interfaces/FileUploadOptions.md +26 -12
  109. package/docs/api/interfaces/FileUploadProps.md +30 -19
  110. package/docs/api/interfaces/FooterProps.md +1 -1
  111. package/docs/api/interfaces/FormFieldProps.md +1 -1
  112. package/docs/api/interfaces/FormProps.md +1 -1
  113. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  114. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  115. package/docs/api/interfaces/InputProps.md +1 -1
  116. package/docs/api/interfaces/LabelProps.md +1 -1
  117. package/docs/api/interfaces/LoggerConfig.md +1 -1
  118. package/docs/api/interfaces/LoginFormProps.md +1 -1
  119. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  120. package/docs/api/interfaces/NavigationContextType.md +9 -9
  121. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  122. package/docs/api/interfaces/NavigationItem.md +1 -1
  123. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  124. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  125. package/docs/api/interfaces/Organisation.md +1 -1
  126. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  127. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  128. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  129. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  130. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  131. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  132. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  133. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  134. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  135. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  136. package/docs/api/interfaces/PaletteData.md +1 -1
  137. package/docs/api/interfaces/ParsedAddress.md +2 -2
  138. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  139. package/docs/api/interfaces/ProgressProps.md +3 -11
  140. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  141. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  142. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  143. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  144. package/docs/api/interfaces/QuickFix.md +1 -1
  145. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  146. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  147. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  148. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  149. package/docs/api/interfaces/RBACConfig.md +2 -2
  150. package/docs/api/interfaces/RBACContext.md +1 -1
  151. package/docs/api/interfaces/RBACLogger.md +1 -1
  152. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  153. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  154. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  155. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  156. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  157. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  158. package/docs/api/interfaces/RBACResult.md +1 -1
  159. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  160. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  161. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  162. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  163. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  164. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  165. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  166. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  167. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  168. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  169. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  170. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  171. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  172. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  173. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  174. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  175. package/docs/api/interfaces/RouteConfig.md +10 -10
  176. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  177. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  178. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  179. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  180. package/docs/api/interfaces/SetupIssue.md +1 -1
  181. package/docs/api/interfaces/StorageConfig.md +4 -4
  182. package/docs/api/interfaces/StorageFileInfo.md +7 -7
  183. package/docs/api/interfaces/StorageFileMetadata.md +25 -14
  184. package/docs/api/interfaces/StorageListOptions.md +22 -9
  185. package/docs/api/interfaces/StorageListResult.md +4 -4
  186. package/docs/api/interfaces/StorageUploadOptions.md +21 -8
  187. package/docs/api/interfaces/StorageUploadResult.md +6 -6
  188. package/docs/api/interfaces/StorageUrlOptions.md +19 -6
  189. package/docs/api/interfaces/StyleImport.md +1 -1
  190. package/docs/api/interfaces/SwitchProps.md +1 -1
  191. package/docs/api/interfaces/TabsContentProps.md +1 -1
  192. package/docs/api/interfaces/TabsListProps.md +1 -1
  193. package/docs/api/interfaces/TabsProps.md +1 -1
  194. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  195. package/docs/api/interfaces/TextareaProps.md +1 -1
  196. package/docs/api/interfaces/ToastActionElement.md +1 -1
  197. package/docs/api/interfaces/ToastProps.md +1 -1
  198. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  199. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  200. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  201. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  202. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  203. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  204. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  205. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  206. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  207. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  208. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  209. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  210. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  211. package/docs/api/interfaces/UseResolvedScopeOptions.md +5 -5
  212. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  213. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  214. package/docs/api/interfaces/UserEventAccess.md +11 -11
  215. package/docs/api/interfaces/UserMenuProps.md +1 -1
  216. package/docs/api/interfaces/UserProfile.md +1 -1
  217. package/docs/api/modules.md +165 -106
  218. package/docs/api-reference/components.md +15 -7
  219. package/docs/api-reference/providers.md +2 -2
  220. package/docs/api-reference/rpc-functions.md +1 -0
  221. package/docs/best-practices/README.md +1 -1
  222. package/docs/best-practices/deployment.md +8 -8
  223. package/docs/getting-started/examples/README.md +2 -2
  224. package/docs/getting-started/installation-guide.md +4 -4
  225. package/docs/getting-started/quick-start.md +3 -3
  226. package/docs/migration/MIGRATION_GUIDE.md +3 -3
  227. package/docs/migration/README.md +18 -0
  228. package/docs/migration/database-changes-december-2025.md +767 -0
  229. package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
  230. package/docs/rbac/compliance/compliance-guide.md +2 -2
  231. package/docs/rbac/event-based-apps.md +2 -2
  232. package/docs/rbac/getting-started.md +2 -2
  233. package/docs/rbac/quick-start.md +2 -2
  234. package/docs/security/README.md +4 -4
  235. package/docs/standards/07-rbac-and-rls-standard.md +430 -7
  236. package/docs/troubleshooting/README.md +2 -2
  237. package/docs/troubleshooting/migration.md +3 -3
  238. package/package.json +1 -3
  239. package/scripts/check-pace-core-compliance.cjs +1 -1
  240. package/scripts/check-pace-core-compliance.js +1 -1
  241. package/src/__tests__/fixtures/supabase.ts +301 -0
  242. package/src/__tests__/public-recipe-view.test.ts +19 -19
  243. package/src/__tests__/rls-policies.test.ts +210 -74
  244. package/src/components/AddressField/AddressField.test.tsx +42 -0
  245. package/src/components/AddressField/AddressField.tsx +71 -60
  246. package/src/components/AddressField/README.md +7 -6
  247. package/src/components/Alert/Alert.test.tsx +50 -10
  248. package/src/components/Alert/Alert.tsx +5 -3
  249. package/src/components/Avatar/Avatar.test.tsx +95 -43
  250. package/src/components/Avatar/Avatar.tsx +16 -16
  251. package/src/components/Button/Button.test.tsx +2 -1
  252. package/src/components/Button/Button.tsx +3 -3
  253. package/src/components/Calendar/Calendar.test.tsx +53 -37
  254. package/src/components/Calendar/Calendar.tsx +409 -82
  255. package/src/components/Card/Card.test.tsx +7 -4
  256. package/src/components/Card/Card.tsx +3 -6
  257. package/src/components/Checkbox/Checkbox.tsx +2 -2
  258. package/src/components/DataTable/components/ActionButtons.tsx +5 -5
  259. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  260. package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
  261. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
  262. package/src/components/DataTable/components/DataTableBody.tsx +12 -12
  263. package/src/components/DataTable/components/DataTableCore.tsx +3 -3
  264. package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
  265. package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
  266. package/src/components/DataTable/components/EditableRow.tsx +2 -2
  267. package/src/components/DataTable/components/EmptyState.tsx +3 -3
  268. package/src/components/DataTable/components/GroupHeader.tsx +2 -2
  269. package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
  270. package/src/components/DataTable/components/ImportModal.tsx +4 -4
  271. package/src/components/DataTable/components/LoadingState.tsx +1 -1
  272. package/src/components/DataTable/components/PaginationControls.tsx +11 -11
  273. package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
  274. package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
  275. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
  276. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
  277. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
  278. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
  279. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
  280. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
  281. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
  282. package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
  283. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
  284. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
  285. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
  286. package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
  287. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
  288. package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
  289. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
  290. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
  291. package/src/components/Dialog/Dialog.tsx +2 -2
  292. package/src/components/EventSelector/EventSelector.tsx +7 -7
  293. package/src/components/FileDisplay/FileDisplay.tsx +291 -179
  294. package/src/components/FileUpload/FileUpload.tsx +7 -4
  295. package/src/components/Header/Header.test.tsx +28 -0
  296. package/src/components/Header/Header.tsx +22 -9
  297. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
  298. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
  299. package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
  301. package/src/components/OrganisationSelector/OrganisationSelector.tsx +42 -22
  302. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
  303. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
  304. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
  305. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
  306. package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
  307. package/src/components/PaceAppLayout/test-setup.tsx +1 -0
  308. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
  309. package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
  310. package/src/components/Progress/Progress.test.tsx +18 -19
  311. package/src/components/Progress/Progress.tsx +31 -32
  312. package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
  313. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
  314. package/src/components/Select/Select.test.tsx +4 -1
  315. package/src/components/Select/Select.tsx +65 -20
  316. package/src/components/Switch/Switch.test.tsx +2 -1
  317. package/src/components/Switch/Switch.tsx +1 -1
  318. package/src/components/Toast/Toast.tsx +1 -1
  319. package/src/components/Tooltip/Tooltip.test.tsx +8 -2
  320. package/src/components/UserMenu/UserMenu.tsx +3 -3
  321. package/src/eslint-rules/pace-core-compliance.cjs +0 -2
  322. package/src/eslint-rules/pace-core-compliance.js +0 -2
  323. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
  324. package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
  325. package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
  326. package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
  327. package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
  328. package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
  329. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -1
  330. package/src/hooks/__tests__/usePublicEvent.test.ts +608 -0
  331. package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
  332. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +67 -24
  333. package/src/hooks/index.ts +1 -1
  334. package/src/hooks/public/usePublicEvent.ts +10 -10
  335. package/src/hooks/public/usePublicFileDisplay.ts +173 -87
  336. package/src/hooks/useAppConfig.ts +24 -5
  337. package/src/hooks/useFileDisplay.ts +298 -36
  338. package/src/hooks/useFileReference.ts +56 -11
  339. package/src/hooks/useFileUrl.ts +1 -1
  340. package/src/hooks/useInactivityTracker.ts +16 -7
  341. package/src/hooks/usePermissionCache.test.ts +85 -8
  342. package/src/hooks/useQueryCache.ts +27 -6
  343. package/src/hooks/useSecureDataAccess.test.ts +87 -42
  344. package/src/hooks/useSecureDataAccess.ts +95 -48
  345. package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
  346. package/src/providers/services/EventServiceProvider.tsx +37 -17
  347. package/src/providers/services/InactivityServiceProvider.tsx +4 -4
  348. package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
  349. package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
  350. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
  351. package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
  352. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
  353. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
  354. package/src/rbac/api.ts +240 -36
  355. package/src/rbac/cache-invalidation.ts +21 -7
  356. package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
  357. package/src/rbac/components/NavigationGuard.tsx +23 -63
  358. package/src/rbac/components/NavigationProvider.test.tsx +52 -23
  359. package/src/rbac/components/NavigationProvider.tsx +13 -11
  360. package/src/rbac/components/PagePermissionGuard.tsx +77 -203
  361. package/src/rbac/components/PagePermissionProvider.tsx +13 -11
  362. package/src/rbac/components/PermissionEnforcer.tsx +24 -62
  363. package/src/rbac/components/RoleBasedRouter.tsx +14 -12
  364. package/src/rbac/components/SecureDataProvider.tsx +13 -11
  365. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
  366. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
  367. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
  368. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
  369. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
  370. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
  371. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
  372. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
  373. package/src/rbac/engine.ts +4 -2
  374. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
  375. package/src/rbac/hooks/index.ts +3 -0
  376. package/src/rbac/hooks/useCan.test.ts +101 -53
  377. package/src/rbac/hooks/usePermissions.ts +108 -41
  378. package/src/rbac/hooks/useRBAC.test.ts +11 -3
  379. package/src/rbac/hooks/useRBAC.ts +83 -40
  380. package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
  381. package/src/rbac/hooks/useResolvedScope.ts +128 -70
  382. package/src/rbac/hooks/useSecureSupabase.ts +36 -19
  383. package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
  384. package/src/rbac/request-deduplication.ts +1 -1
  385. package/src/rbac/secureClient.ts +72 -12
  386. package/src/rbac/security.ts +29 -23
  387. package/src/rbac/types.ts +10 -0
  388. package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
  389. package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
  390. package/src/rbac/utils/__tests__/eventContext.test.ts +8 -3
  391. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +74 -12
  392. package/src/rbac/utils/contextValidator.ts +288 -0
  393. package/src/rbac/utils/eventContext.ts +52 -3
  394. package/src/services/AuthService.ts +37 -8
  395. package/src/services/EventService.ts +165 -21
  396. package/src/services/OrganisationService.ts +125 -137
  397. package/src/services/__tests__/EventService.test.ts +26 -21
  398. package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
  399. package/src/services/__tests__/OrganisationService.test.ts +218 -86
  400. package/src/types/database.generated.ts +166 -201
  401. package/src/types/file-reference.ts +13 -10
  402. package/src/types/supabase.ts +2 -2
  403. package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
  404. package/src/utils/app/appNameResolver.test.ts +346 -73
  405. package/src/utils/context/superAdminOverride.ts +58 -0
  406. package/src/utils/file-reference/index.ts +65 -37
  407. package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
  408. package/src/utils/google-places/googlePlacesUtils.ts +1 -1
  409. package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
  410. package/src/utils/google-places/types.ts +1 -1
  411. package/src/utils/request-deduplication.ts +4 -4
  412. package/src/utils/security/secureDataAccess.test.ts +1 -1
  413. package/src/utils/security/secureDataAccess.ts +7 -4
  414. package/src/utils/storage/README.md +1 -1
  415. package/src/utils/storage/helpers.test.ts +1 -1
  416. package/src/utils/storage/helpers.ts +38 -19
  417. package/src/utils/storage/types.ts +15 -8
  418. package/src/utils/validation/__tests__/csrf.test.ts +105 -0
  419. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
  420. package/src/vite-env.d.ts +2 -2
  421. package/dist/chunk-3GOZZZYH.js.map +0 -1
  422. package/dist/chunk-DDM4CCYT.js.map +0 -1
  423. package/dist/chunk-E7UAOUMY.js +0 -75
  424. package/dist/chunk-E7UAOUMY.js.map +0 -1
  425. package/dist/chunk-F2IMUDXZ.js.map +0 -1
  426. package/dist/chunk-HEHYGYOX.js.map +0 -1
  427. package/dist/chunk-IM4QE42D.js.map +0 -1
  428. package/dist/chunk-MX64ZF6I.js.map +0 -1
  429. package/dist/chunk-SAUPYVLF.js.map +0 -1
  430. package/dist/chunk-THRPYOFK.js.map +0 -1
  431. package/dist/chunk-UCQSRW7Z.js.map +0 -1
  432. package/dist/chunk-VGZZXKBR.js.map +0 -1
  433. package/dist/chunk-YGPFYGA6.js.map +0 -1
  434. package/dist/chunk-YHCN776L.js.map +0 -1
  435. /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-WKRZD47S.js.map} +0 -0
  436. /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
  437. /package/dist/{api-YP7XD5L6.js.map → api-IHKALJZD.js.map} +0 -0
  438. /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
@@ -31,6 +31,11 @@ vi.mock('../../utils/eventContext', () => ({
31
31
  createScopeFromEvent: vi.fn()
32
32
  }));
33
33
 
34
+ // Mock useResolvedScope hook
35
+ vi.mock('../../hooks/useResolvedScope', () => ({
36
+ useResolvedScope: vi.fn()
37
+ }));
38
+
34
39
  // Mock the Logger module
35
40
  vi.mock('../../../utils/core/logger', () => {
36
41
  const mockLoggerInstance = {
@@ -48,6 +53,7 @@ import { createLogger } from '../../../utils/core/logger';
48
53
  const getMockLogger = () => createLogger('test');
49
54
 
50
55
  import { createScopeFromEvent } from '../../utils/eventContext';
56
+ import { useResolvedScope } from '../../hooks/useResolvedScope';
51
57
 
52
58
  // Mock data
53
59
  const mockUser = {
@@ -80,6 +86,7 @@ const TestLoading = () => (
80
86
  describe('PermissionEnforcer Component', () => {
81
87
  const mockUseMultiplePermissions = vi.mocked(useMultiplePermissions);
82
88
  const mockCreateScopeFromEvent = vi.mocked(createScopeFromEvent);
89
+ const mockUseResolvedScope = vi.mocked(useResolvedScope);
83
90
 
84
91
  beforeEach(() => {
85
92
  vi.clearAllMocks();
@@ -92,6 +99,17 @@ describe('PermissionEnforcer Component', () => {
92
99
  supabase: {} as any
93
100
  });
94
101
 
102
+ // Mock useResolvedScope to return resolved scope immediately
103
+ mockUseResolvedScope.mockReturnValue({
104
+ resolvedScope: {
105
+ organisationId: 'org-123',
106
+ eventId: 'event-123',
107
+ appId: 'app-123'
108
+ },
109
+ isLoading: false,
110
+ error: null
111
+ });
112
+
95
113
  mockUseMultiplePermissions.mockReturnValue({
96
114
  results: {
97
115
  'read:events': true,
@@ -243,10 +261,11 @@ describe('PermissionEnforcer Component', () => {
243
261
 
244
262
  expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
245
263
  'user-123',
246
- expect.objectContaining({
264
+ {
247
265
  organisationId: 'org-123',
248
- eventId: 'event-123'
249
- }),
266
+ eventId: 'event-123',
267
+ appId: 'app-123'
268
+ },
250
269
  ['read:events'], // singlePermission only includes read:events
251
270
  true
252
271
  );
@@ -277,10 +296,11 @@ describe('PermissionEnforcer Component', () => {
277
296
  // Should check all permissions when requireAll=true
278
297
  expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
279
298
  'user-123',
280
- expect.objectContaining({
299
+ {
281
300
  organisationId: 'org-123',
282
- eventId: 'event-123'
283
- }),
301
+ eventId: 'event-123',
302
+ appId: 'app-123'
303
+ },
284
304
  ['read:events', 'update:events'],
285
305
  true
286
306
  );
@@ -393,16 +413,18 @@ describe('PermissionEnforcer Component', () => {
393
413
 
394
414
  expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
395
415
  'user-123',
396
- expect.objectContaining({
416
+ {
397
417
  organisationId: 'org-123',
398
- eventId: 'event-123'
399
- }),
418
+ eventId: 'event-123',
419
+ appId: 'app-123'
420
+ },
400
421
  ['read:events', 'update:events'], // mockPermissions includes both
401
422
  true
402
423
  );
403
424
  });
404
425
 
405
- it('resolves scope from organisation only', async () => {
426
+ it('resolves scope from organisation only (org-required app)', async () => {
427
+ // For org-required apps, organisation is primary context, event is optional
406
428
  mockUseUnifiedAuthFn.mockReturnValue({
407
429
  user: mockUser,
408
430
  selectedOrganisation: { id: 'org-123' },
@@ -410,6 +432,16 @@ describe('PermissionEnforcer Component', () => {
410
432
  supabase: {} as any
411
433
  });
412
434
 
435
+ mockUseResolvedScope.mockReturnValue({
436
+ resolvedScope: {
437
+ organisationId: 'org-123',
438
+ eventId: undefined,
439
+ appId: 'app-123'
440
+ },
441
+ isLoading: false,
442
+ error: null
443
+ });
444
+
413
445
  mockUseMultiplePermissions.mockReturnValue({
414
446
  results: { 'read:events': true } as Record<string, boolean>,
415
447
  isLoading: false,
@@ -432,27 +464,33 @@ describe('PermissionEnforcer Component', () => {
432
464
 
433
465
  expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
434
466
  'user-123',
435
- expect.objectContaining({
467
+ {
436
468
  organisationId: 'org-123',
437
- eventId: undefined
438
- }),
469
+ eventId: undefined,
470
+ appId: 'app-123'
471
+ },
439
472
  ['read:events', 'update:events'], // mockPermissions includes both
440
473
  true
441
474
  );
442
475
  });
443
476
 
444
- it('resolves scope from event context when organisation not available', async () => {
477
+ it('resolves scope from event context when organisation not available (event-required app)', async () => {
478
+ // For event-required apps, selectedOrganisation is null, org is derived from event
445
479
  mockUseUnifiedAuthFn.mockReturnValue({
446
480
  user: mockUser,
447
- selectedOrganisation: null,
481
+ selectedOrganisation: null, // Not available for event-required apps
448
482
  selectedEvent: { event_id: 'event-123' },
449
483
  supabase: {} as any
450
484
  });
451
485
 
452
- mockCreateScopeFromEvent.mockResolvedValue({
453
- organisationId: 'resolved-org',
454
- eventId: 'event-123',
455
- appId: 'resolved-app'
486
+ mockUseResolvedScope.mockReturnValue({
487
+ resolvedScope: {
488
+ organisationId: 'resolved-org',
489
+ eventId: 'event-123',
490
+ appId: 'resolved-app'
491
+ },
492
+ isLoading: false,
493
+ error: null
456
494
  });
457
495
 
458
496
  mockUseMultiplePermissions.mockReturnValue({
@@ -475,13 +513,13 @@ describe('PermissionEnforcer Component', () => {
475
513
  expect(screen.getByTestId('test-component')).toBeInTheDocument();
476
514
  }, { interval: 10 });
477
515
 
478
- expect(mockCreateScopeFromEvent).toHaveBeenCalledWith({}, 'event-123');
479
516
  expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
480
517
  'user-123',
481
- expect.objectContaining({
518
+ {
482
519
  organisationId: 'resolved-org',
483
- eventId: 'event-123'
484
- }),
520
+ eventId: 'event-123',
521
+ appId: 'resolved-app'
522
+ },
485
523
  ['read:events', 'update:events'], // mockPermissions includes both
486
524
  true
487
525
  );
@@ -496,7 +534,11 @@ describe('PermissionEnforcer Component', () => {
496
534
  });
497
535
 
498
536
  const error = new Error('Could not resolve organisation from event');
499
- mockCreateScopeFromEvent.mockRejectedValue(error);
537
+ mockUseResolvedScope.mockReturnValue({
538
+ resolvedScope: null,
539
+ isLoading: false,
540
+ error
541
+ });
500
542
 
501
543
  render(
502
544
  <PermissionEnforcer
@@ -521,6 +563,12 @@ describe('PermissionEnforcer Component', () => {
521
563
  supabase: null
522
564
  });
523
565
 
566
+ mockUseResolvedScope.mockReturnValue({
567
+ resolvedScope: null,
568
+ isLoading: true,
569
+ error: null
570
+ });
571
+
524
572
  render(
525
573
  <PermissionEnforcer
526
574
  permissions={mockPermissions}
@@ -531,9 +579,7 @@ describe('PermissionEnforcer Component', () => {
531
579
  </PermissionEnforcer>
532
580
  );
533
581
 
534
- await waitFor(() => {
535
- expect(screen.getByTestId('test-component')).toBeInTheDocument();
536
- }, { interval: 10 });
582
+ expect(screen.getByText('Checking permissions...')).toBeInTheDocument();
537
583
  });
538
584
  });
539
585
 
@@ -798,10 +844,11 @@ describe('PermissionEnforcer Component', () => {
798
844
 
799
845
  expect(mockUseMultiplePermissions).toHaveBeenCalledWith(
800
846
  '',
801
- expect.objectContaining({
847
+ {
802
848
  organisationId: 'org-123',
803
- eventId: 'event-123'
804
- }),
849
+ eventId: 'event-123',
850
+ appId: 'app-123'
851
+ },
805
852
  ['read:events', 'update:events'], // mockPermissions includes both
806
853
  true
807
854
  );
@@ -27,6 +27,12 @@ vi.mock('../../../providers/services/UnifiedAuthProvider', () => ({
27
27
  UnifiedAuthProvider: ({ children }: { children: React.ReactNode }) => <>{children}</>,
28
28
  }));
29
29
 
30
+ // Mock useResolvedScope
31
+ const mockUseResolvedScopeFn = vi.fn();
32
+ vi.mock('../../hooks/useResolvedScope', () => ({
33
+ useResolvedScope: () => mockUseResolvedScopeFn(),
34
+ }));
35
+
30
36
  // Mock React Router
31
37
  vi.mock('react-router-dom', async () => {
32
38
  const actual = await vi.importActual('react-router-dom');
@@ -49,7 +55,7 @@ const mockUser = {
49
55
  const mockScope = {
50
56
  organisationId: 'org-123',
51
57
  eventId: 'event-123',
52
- appId: 'app-123'
58
+ appId: undefined // Most tests expect undefined
53
59
  };
54
60
 
55
61
  const mockRoutes = [
@@ -101,7 +107,20 @@ describe('RoleBasedRouter Component', () => {
101
107
  mockUseUnifiedAuthFn.mockReturnValue({
102
108
  user: mockUser,
103
109
  selectedOrganisation: { id: 'org-123' },
104
- selectedEvent: { event_id: 'event-123' }
110
+ selectedEvent: { event_id: 'event-123' },
111
+ supabase: {} as any,
112
+ });
113
+
114
+ // Mock useResolvedScope to return resolved scope
115
+ // Note: appId is undefined in some tests, so we'll set it conditionally
116
+ mockUseResolvedScopeFn.mockReturnValue({
117
+ resolvedScope: {
118
+ organisationId: 'org-123',
119
+ eventId: 'event-123',
120
+ appId: undefined, // Default to undefined for most tests
121
+ },
122
+ isLoading: false,
123
+ error: null,
105
124
  });
106
125
 
107
126
  mockUseLocation.mockReturnValue({
@@ -233,11 +252,16 @@ describe('RoleBasedRouter Component', () => {
233
252
  expect.objectContaining({
234
253
  organisationId: 'org-123',
235
254
  eventId: 'event-123',
236
- appId: undefined
237
255
  }),
238
256
  'read:dashboard',
239
257
  'dashboard'
240
258
  );
259
+ // Check that appId is either undefined or matches expected value
260
+ const call = mockUseCan.mock.calls.find(c => c[0] === 'user-123' && c[2] === 'read:dashboard');
261
+ expect(call).toBeDefined();
262
+ if (call) {
263
+ expect(call[1].appId).toBeUndefined();
264
+ }
241
265
  });
242
266
 
243
267
  it('denies access to routes without permissions', async () => {
@@ -639,11 +663,16 @@ describe('RoleBasedRouter Component', () => {
639
663
  expect.objectContaining({
640
664
  organisationId: 'org-123',
641
665
  eventId: 'event-123',
642
- appId: undefined
643
666
  }),
644
667
  'read:dashboard',
645
668
  'dashboard'
646
669
  );
670
+ // Check that appId is either undefined or matches expected value
671
+ const call = mockUseCan.mock.calls.find(c => c[0] === '' && c[2] === 'read:dashboard');
672
+ expect(call).toBeDefined();
673
+ if (call) {
674
+ expect(call[1].appId).toBeUndefined();
675
+ }
647
676
  });
648
677
 
649
678
  it('handles missing organisation context', async () => {
@@ -727,12 +756,17 @@ describe('RoleBasedRouter Component', () => {
727
756
  expect.objectContaining({
728
757
  organisationId: 'org-123',
729
758
  eventId: 'event-123',
730
- appId: undefined
731
759
  }),
732
760
  'admin:system',
733
761
  'admin'
734
762
  );
735
763
  }, { interval: 10 });
764
+ // Check that appId is either undefined or matches expected value
765
+ const call = mockUseCan.mock.calls.find(c => c[0] === 'user-123' && c[2] === 'admin:system');
766
+ expect(call).toBeDefined();
767
+ if (call) {
768
+ expect(call[1].appId).toBeUndefined();
769
+ }
736
770
  });
737
771
  });
738
772
  });
@@ -61,6 +61,12 @@ vi.mock('../../../hooks/useSecureDataAccess', () => ({
61
61
  }))
62
62
  }));
63
63
 
64
+ // Mock useResolvedScope
65
+ const mockUseResolvedScopeFn = vi.fn();
66
+ vi.mock('../../hooks/useResolvedScope', () => ({
67
+ useResolvedScope: () => mockUseResolvedScopeFn(),
68
+ }));
69
+
64
70
  // Test data
65
71
  const mockUser = {
66
72
  user: {
@@ -147,7 +153,18 @@ describe('SecureDataProvider', () => {
147
153
  beforeEach(() => {
148
154
  vi.clearAllMocks();
149
155
 
150
- mockUseUnifiedAuthFn.mockReturnValue(mockUser);
156
+ mockUseUnifiedAuthFn.mockReturnValue({
157
+ ...mockUser,
158
+ supabase: {} as any,
159
+ });
160
+
161
+ // Mock useResolvedScope to return resolved scope
162
+ mockUseResolvedScopeFn.mockReturnValue({
163
+ resolvedScope: mockScope,
164
+ isLoading: false,
165
+ error: null,
166
+ });
167
+
151
168
  mockValidateContext.mockImplementation(() => {});
152
169
  });
153
170
 
@@ -278,8 +295,22 @@ describe('SecureDataProvider', () => {
278
295
  expect(screen.getByTestId('data-access-allowed')).toHaveTextContent('false');
279
296
  });
280
297
 
281
- it('should deny data access when organisation context is missing', () => {
282
- mockUseUnifiedAuthFn.mockReturnValue({ ...mockUser, selectedOrganisation: null });
298
+ it('should deny data access when organisation context is missing (org-required app)', () => {
299
+ // For org-required apps, selectedOrganisation is required
300
+ // For event-required apps, selectedOrganisation is null and org is derived from event
301
+ mockUseUnifiedAuthFn.mockReturnValue({
302
+ ...mockUser,
303
+ selectedOrganisation: null,
304
+ selectedEvent: null, // No event either, so no context available
305
+ supabase: {} as any,
306
+ });
307
+
308
+ // Mock useResolvedScope to return null scope when no context available
309
+ mockUseResolvedScopeFn.mockReturnValue({
310
+ resolvedScope: null,
311
+ isLoading: false,
312
+ error: null,
313
+ });
283
314
 
284
315
  renderWithProviders(
285
316
  <TestWrapper>
@@ -411,7 +442,19 @@ describe('SecureDataProvider', () => {
411
442
  });
412
443
 
413
444
  it('should handle missing organisation context gracefully', () => {
414
- mockUseUnifiedAuthFn.mockReturnValue({ ...mockUser, selectedOrganisation: null });
445
+ mockUseUnifiedAuthFn.mockReturnValue({
446
+ ...mockUser,
447
+ selectedOrganisation: null,
448
+ selectedEvent: null, // No event either
449
+ supabase: {} as any,
450
+ });
451
+
452
+ // Mock useResolvedScope to return null scope when no context available
453
+ mockUseResolvedScopeFn.mockReturnValue({
454
+ resolvedScope: null,
455
+ isLoading: false,
456
+ error: null,
457
+ });
415
458
 
416
459
  renderWithProviders(
417
460
  <TestWrapper>
@@ -296,7 +296,7 @@ export class RBACEngine {
296
296
 
297
297
  // Check organisation role
298
298
  if (scope.organisationId) {
299
- const { data: orgRole } = await this.supabase
299
+ const { data: orgRoles } = await this.supabase
300
300
  .from('rbac_organisation_roles')
301
301
  .select('role')
302
302
  .eq('user_id', userId)
@@ -305,7 +305,9 @@ export class RBACEngine {
305
305
  .is('revoked_at', null)
306
306
  .lte('valid_from', now)
307
307
  .or(`valid_to.is.null,valid_to.gte.${now}`)
308
- .single() as { data: { role: string } | null; error: any };
308
+ .limit(1) as { data: Array<{ role: string }> | null; error: any };
309
+
310
+ const orgRole = orgRoles?.[0];
309
311
 
310
312
  if (orgRole?.role === 'org_admin') {
311
313
  rbacCache.set(cacheKey, 'admin', 60000);