@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
@@ -7,8 +7,8 @@
7
7
  * Comprehensive tests for the usePermissionCache hook covering all critical functionality.
8
8
  */
9
9
 
10
- import { renderHook, waitFor, act } from '@testing-library/react';
11
- import { vi, describe, it, expect, beforeEach, afterEach } from 'vitest';
10
+ import { renderHook, act } from '@testing-library/react';
11
+ import { vi, describe, it, expect, beforeEach } from 'vitest';
12
12
  import { usePermissionCache } from './usePermissionCache';
13
13
 
14
14
  // Mock the dependencies
@@ -29,6 +29,16 @@ vi.mock('../rbac/api', () => ({
29
29
  isPermittedCached: vi.fn()
30
30
  }));
31
31
 
32
+ const loggerSpy = vi.hoisted(() => ({
33
+ warn: vi.fn(),
34
+ error: vi.fn()
35
+ }));
36
+
37
+ vi.mock('../utils/core/logger', () => ({
38
+ logger: loggerSpy,
39
+ createLogger: () => loggerSpy
40
+ }));
41
+
32
42
  import { useUnifiedAuth } from '../providers/services/UnifiedAuthProvider';
33
43
  import { useOrganisations } from './useOrganisations';
34
44
  import { useEvents } from './useEvents';
@@ -41,7 +51,7 @@ const mockIsPermittedCached = vi.mocked(isPermittedCached);
41
51
  describe('usePermissionCache', () => {
42
52
  beforeEach(() => {
43
53
  vi.clearAllMocks();
44
-
54
+
45
55
  // Setup default mocks
46
56
  mockUseUnifiedAuthFn.mockReturnValue({
47
57
  user: { id: 'user-123' },
@@ -50,19 +60,19 @@ describe('usePermissionCache', () => {
50
60
  selectedOrganisationId: 'org-123',
51
61
  selectedEventId: undefined
52
62
  } as any);
53
-
63
+
54
64
  mockUseOrganisations.mockReturnValue({
55
65
  selectedOrganisation: { id: 'org-123' }
56
66
  } as any);
57
-
67
+
58
68
  mockUseEvents.mockReturnValue({
59
69
  selectedEvent: null
60
70
  } as any);
61
-
71
+
62
72
  mockIsPermittedCached.mockResolvedValue(true);
63
73
  });
64
74
 
65
- describe('Hook Initialization', () => {
75
+ describe('Hook Initialization', () => {
66
76
  it('initializes with default configuration', () => {
67
77
  const { result } = renderHook(() => usePermissionCache());
68
78
 
@@ -130,6 +140,16 @@ describe('usePermissionCache', () => {
130
140
  expect(results.every(r => r.hasPermission)).toBe(true);
131
141
  });
132
142
 
143
+ it('handles empty permission arrays gracefully', async () => {
144
+ const { result } = renderHook(() => usePermissionCache());
145
+
146
+ const results = await result.current.checkMultiplePermissions([]);
147
+
148
+ expect(results).toEqual([]);
149
+ expect(mockIsPermittedCached).not.toHaveBeenCalled();
150
+ expect(loggerSpy.warn).toHaveBeenCalled();
151
+ });
152
+
133
153
  it('handles permission check errors gracefully', async () => {
134
154
  mockIsPermittedCached.mockRejectedValueOnce(new Error('Permission check failed'));
135
155
 
@@ -137,6 +157,7 @@ describe('usePermissionCache', () => {
137
157
 
138
158
  const hasPermission = await result.current.checkPermission('read', 'users');
139
159
  expect(hasPermission).toBe(false);
160
+ expect(loggerSpy.error).toHaveBeenCalled();
140
161
  });
141
162
 
142
163
  it('handles missing user context gracefully', () => {
@@ -153,6 +174,23 @@ describe('usePermissionCache', () => {
153
174
  expect(result.current).toBeDefined();
154
175
  expect(result.current.checkPermission).toBeInstanceOf(Function);
155
176
  });
177
+
178
+ it('deduplicates concurrent permission checks', async () => {
179
+ mockIsPermittedCached.mockImplementation(
180
+ () => new Promise(resolve => setTimeout(() => resolve(true), 50))
181
+ );
182
+
183
+ const { result } = renderHook(() => usePermissionCache());
184
+
185
+ const [first, second] = await Promise.all([
186
+ result.current.checkPermission('read', 'users'),
187
+ result.current.checkPermission('read', 'users')
188
+ ]);
189
+
190
+ expect(first).toBe(true);
191
+ expect(second).toBe(true);
192
+ expect(mockIsPermittedCached).toHaveBeenCalledTimes(1);
193
+ });
156
194
  });
157
195
 
158
196
  describe('Cache Management', () => {
@@ -196,10 +234,23 @@ describe('usePermissionCache', () => {
196
234
 
197
235
  // Check again - should not use cache
198
236
  await result.current.checkPermission('read', 'users');
199
-
237
+
200
238
  expect(mockIsPermittedCached).toHaveBeenCalledTimes(2);
201
239
  });
202
240
 
241
+ it('invalidates cache entries by pattern', async () => {
242
+ const { result } = renderHook(() => usePermissionCache());
243
+
244
+ await result.current.checkPermission('read', 'dashboard');
245
+ await result.current.checkPermission('read', 'admin');
246
+
247
+ result.current.invalidateCache('dashboard');
248
+
249
+ await result.current.checkPermission('read', 'dashboard');
250
+
251
+ expect(mockIsPermittedCached).toHaveBeenCalledTimes(3);
252
+ });
253
+
203
254
  it('respects max cache size', async () => {
204
255
  const { result } = renderHook(() => usePermissionCache({
205
256
  maxCacheSize: 2
@@ -246,6 +297,32 @@ describe('usePermissionCache', () => {
246
297
  expect(debugInfo.totalChecks).toBe(2);
247
298
  });
248
299
 
300
+ it('returns cached permissions for a page', async () => {
301
+ mockIsPermittedCached
302
+ .mockResolvedValueOnce(true)
303
+ .mockResolvedValueOnce(false)
304
+ .mockResolvedValueOnce(true)
305
+ .mockResolvedValueOnce(false);
306
+
307
+ const { result } = renderHook(() => usePermissionCache());
308
+
309
+ await result.current.checkMultiplePermissions([
310
+ ['read', 'dashboard'],
311
+ ['create', 'dashboard'],
312
+ ['update', 'dashboard'],
313
+ ['delete', 'dashboard']
314
+ ]);
315
+
316
+ const cachedPermissions = result.current.getCachedPermissions('dashboard');
317
+
318
+ expect(cachedPermissions).toEqual([
319
+ { operation: 'read', hasPermission: true },
320
+ { operation: 'create', hasPermission: false },
321
+ { operation: 'update', hasPermission: true },
322
+ { operation: 'delete', hasPermission: false }
323
+ ]);
324
+ });
325
+
249
326
  it('tracks average response time', async () => {
250
327
  const { result } = renderHook(() => usePermissionCache());
251
328
 
@@ -51,6 +51,27 @@ function runCacheCleanup() {
51
51
  if (typeof window !== 'undefined' && !cleanupTimer) {
52
52
  cleanupTimer = setInterval(runCacheCleanup, CLEANUP_INTERVAL_MS);
53
53
  log.debug('Query cache cleanup initialized.');
54
+
55
+ // Cleanup on page unload to prevent memory leaks
56
+ window.addEventListener('beforeunload', () => {
57
+ if (cleanupTimer) {
58
+ clearInterval(cleanupTimer);
59
+ cleanupTimer = null;
60
+ log.debug('Query cache cleanup timer cleared on page unload.');
61
+ }
62
+ });
63
+ }
64
+
65
+ /**
66
+ * Manually cleanup the query cache cleanup timer
67
+ * Useful for testing or when the module is reloaded
68
+ */
69
+ export function cleanupQueryCache(): void {
70
+ if (cleanupTimer) {
71
+ clearInterval(cleanupTimer);
72
+ cleanupTimer = null;
73
+ log.debug('Query cache cleanup timer cleared.');
74
+ }
54
75
  }
55
76
 
56
77
  export interface UseQueryCacheOptions {
@@ -91,12 +112,12 @@ export interface UseQueryCacheReturn {
91
112
  * const { getCachedQuery } = useQueryCache(supabase);
92
113
  *
93
114
  * const person = await getCachedQuery(
94
- * 'pace_person',
115
+ * 'core_person',
95
116
  * 'user_id',
96
117
  * userId,
97
118
  * async () => {
98
119
  * const { data } = await supabase
99
- * .from('pace_person')
120
+ * .from('core_person')
100
121
  * .select('id, first_name, last_name, email')
101
122
  * .eq('user_id', userId)
102
123
  * .single();
@@ -199,7 +220,7 @@ export function useQueryCache(supabase?: SupabaseClient<Database>): UseQueryCach
199
220
  */
200
221
  export const queryCacheHelpers = {
201
222
  /**
202
- * Cache pace_person queries by user_id
223
+ * Cache core_person queries by user_id
203
224
  * TTL: 5 minutes
204
225
  */
205
226
  pacePersonByUserId: <T>(
@@ -207,7 +228,7 @@ export const queryCacheHelpers = {
207
228
  userId: string,
208
229
  fetchFn: () => Promise<T>
209
230
  ): Promise<T> => {
210
- const cacheKey = `pace_person:user_id:${userId}`;
231
+ const cacheKey = `core_person:user_id:${userId}`;
211
232
  const now = Date.now();
212
233
  const ttl = 300 * 1000; // 5 minutes
213
234
 
@@ -237,7 +258,7 @@ export const queryCacheHelpers = {
237
258
  },
238
259
 
239
260
  /**
240
- * Cache pace_member queries by person_id
261
+ * Cache core_member queries by person_id
241
262
  * TTL: 5 minutes
242
263
  */
243
264
  paceMemberByPersonId: <T>(
@@ -245,7 +266,7 @@ export const queryCacheHelpers = {
245
266
  personId: string,
246
267
  fetchFn: () => Promise<T>
247
268
  ): Promise<T> => {
248
- const cacheKey = `pace_member:person_id:${personId}`;
269
+ const cacheKey = `core_member:person_id:${personId}`;
249
270
  const now = Date.now();
250
271
  const ttl = 300 * 1000; // 5 minutes
251
272
 
@@ -14,6 +14,8 @@ import { useUnifiedAuth } from '../providers';
14
14
  import { useOrganisations } from './useOrganisations';
15
15
  import { setOrganisationContext } from '../utils/context/organisationContext';
16
16
  import { createMockSupabaseClient, createMockQueryBuilderWithData } from '../__tests__/helpers/supabaseMock';
17
+ import { useResolvedScope } from '../rbac/hooks/useResolvedScope';
18
+ import { useSuperAdminBypass } from '../rbac/hooks/useSuperAdminBypass';
17
19
 
18
20
  // Mock the providers
19
21
  vi.mock('../providers', () => ({
@@ -29,11 +31,23 @@ vi.mock('../utils/context/organisationContext', () => ({
29
31
  setOrganisationContext: vi.fn()
30
32
  }));
31
33
 
34
+ // Mock useResolvedScope
35
+ vi.mock('../rbac/hooks/useResolvedScope', () => ({
36
+ useResolvedScope: vi.fn()
37
+ }));
38
+
39
+ // Mock useSuperAdminBypass
40
+ vi.mock('../rbac/hooks/useSuperAdminBypass', () => ({
41
+ useSuperAdminBypass: vi.fn()
42
+ }));
43
+
32
44
 
33
45
  describe('useSecureDataAccess', () => {
34
46
  const mockUseUnifiedAuth = vi.mocked(useUnifiedAuth);
35
47
  const mockUseOrganisations = vi.mocked(useOrganisations);
36
48
  const mockSetOrganisationContext = vi.mocked(setOrganisationContext);
49
+ const mockUseResolvedScope = vi.mocked(useResolvedScope);
50
+ const mockUseSuperAdminBypass = vi.mocked(useSuperAdminBypass);
37
51
 
38
52
  const mockUser = {
39
53
  id: 'user-123',
@@ -93,6 +107,22 @@ describe('useSecureDataAccess', () => {
93
107
  ensureOrganisationContext: vi.fn().mockReturnValue(mockSelectedOrganisation),
94
108
  // Add other required properties
95
109
  } as any);
110
+
111
+ // Mock useResolvedScope to return resolved scope with organisationId
112
+ mockUseResolvedScope.mockReturnValue({
113
+ resolvedScope: {
114
+ organisationId: 'org-123',
115
+ eventId: undefined,
116
+ appId: undefined,
117
+ },
118
+ isLoading: false,
119
+ error: null,
120
+ });
121
+
122
+ // Mock useSuperAdminBypass to return not super admin
123
+ mockUseSuperAdminBypass.mockReturnValue({
124
+ isSuperAdmin: false,
125
+ });
96
126
  });
97
127
 
98
128
  describe('Hook Initialization', () => {
@@ -113,9 +143,10 @@ describe('useSecureDataAccess', () => {
113
143
  expect(mockUseUnifiedAuth).toHaveBeenCalled();
114
144
  });
115
145
 
116
- it('depends on useOrganisations hook', () => {
146
+ it('depends on useResolvedScope hook', () => {
117
147
  renderHook(() => useSecureDataAccess());
118
- expect(mockUseOrganisations).toHaveBeenCalled();
148
+ // useSecureDataAccess now uses useResolvedScope instead of useOrganisations
149
+ expect(mockUseResolvedScope).toHaveBeenCalled();
119
150
  });
120
151
  });
121
152
 
@@ -123,9 +154,9 @@ describe('useSecureDataAccess', () => {
123
154
  it('executes secure query with organisation filtering', async () => {
124
155
  const { result } = renderHook(() => useSecureDataAccess());
125
156
 
126
- const data = await result.current.secureQuery('event', '*', { active: true });
157
+ const data = await result.current.secureQuery('core_events', '*', { active: true });
127
158
 
128
- expect(freshMockSupabase.from).toHaveBeenCalledWith('event');
159
+ expect(freshMockSupabase.from).toHaveBeenCalledWith('core_events');
129
160
  expect(freshMockQueryBuilder.select).toHaveBeenCalledWith('*');
130
161
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
131
162
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('active', true);
@@ -239,9 +270,9 @@ describe('useSecureDataAccess', () => {
239
270
  it('executes secure update with organisation filtering', async () => {
240
271
  const { result } = renderHook(() => useSecureDataAccess());
241
272
 
242
- const data = await result.current.secureUpdate('event', { event_name: 'Updated Event' }, { id: 'event-123' });
273
+ const data = await result.current.secureUpdate('core_events', { event_name: 'Updated Event' }, { id: 'event-123' });
243
274
 
244
- expect(freshMockSupabase.from).toHaveBeenCalledWith('event');
275
+ expect(freshMockSupabase.from).toHaveBeenCalledWith('core_events');
245
276
  expect(freshMockQueryBuilder.update).toHaveBeenCalledWith({ event_name: 'Updated Event' });
246
277
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('id', 'event-123');
247
278
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -276,9 +307,9 @@ describe('useSecureDataAccess', () => {
276
307
  it('executes secure delete with organisation filtering', async () => {
277
308
  const { result } = renderHook(() => useSecureDataAccess());
278
309
 
279
- await result.current.secureDelete('event', { id: 'event-123' });
310
+ await result.current.secureDelete('core_events', { id: 'event-123' });
280
311
 
281
- expect(freshMockSupabase.from).toHaveBeenCalledWith('event');
312
+ expect(freshMockSupabase.from).toHaveBeenCalledWith('core_events');
282
313
  expect(freshMockQueryBuilder.delete).toHaveBeenCalled();
283
314
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('id', 'event-123');
284
315
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -328,15 +359,22 @@ describe('useSecureDataAccess', () => {
328
359
  });
329
360
 
330
361
  it('handles missing organisation context', () => {
331
- mockUseOrganisations.mockReturnValue({
362
+ mockUseUnifiedAuth.mockReturnValue({
363
+ user: mockUser,
364
+ session: mockSession,
365
+ supabase: freshMockSupabase,
366
+ isAuthenticated: true,
367
+ signOut: vi.fn(),
332
368
  selectedOrganisation: null,
333
- getUserRole: vi.fn().mockReturnValue('no_access'),
334
- validateOrganisationAccess: vi.fn().mockResolvedValue(false),
335
- ensureOrganisationContext: vi.fn().mockImplementation(() => {
336
- throw new Error('Organisation context is required but not available');
337
- }),
338
- // Add other required properties
369
+ selectedEvent: null,
339
370
  } as any);
371
+
372
+ // Mock useResolvedScope to return null scope when no context available
373
+ mockUseResolvedScope.mockReturnValue({
374
+ resolvedScope: null,
375
+ isLoading: false,
376
+ error: null,
377
+ });
340
378
 
341
379
  const { result } = renderHook(() => useSecureDataAccess());
342
380
 
@@ -344,21 +382,15 @@ describe('useSecureDataAccess', () => {
344
382
  });
345
383
 
346
384
  it('validates organisation access before operations', async () => {
347
- const mockValidateAccess = vi.fn().mockResolvedValue(true);
348
- mockUseOrganisations.mockReturnValue({
349
- selectedOrganisation: mockSelectedOrganisation,
350
- getUserRole: vi.fn().mockReturnValue('member'),
351
- validateOrganisationAccess: mockValidateAccess,
352
- ensureOrganisationContext: vi.fn().mockReturnValue(mockSelectedOrganisation),
353
- // Add other required properties
354
- } as any);
355
-
385
+ // The hook uses useResolvedScope to get organisationId, which is already mocked in beforeEach
386
+ // The validation happens in validateContext which checks resolvedScope.organisationId
356
387
  const { result } = renderHook(() => useSecureDataAccess());
357
388
 
358
- await result.current.secureQuery('users', '*');
389
+ // Use 'event' table which is in the tablesWithOrganisation list
390
+ await result.current.secureQuery('core_events', '*');
359
391
 
360
- // The hook doesn't call validateOrganisationAccess, it calls ensureOrganisationContext
361
- expect(mockUseOrganisations().ensureOrganisationContext).toHaveBeenCalled();
392
+ // Verify that the query was executed with organisation filter
393
+ expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
362
394
  });
363
395
  });
364
396
 
@@ -394,16 +426,16 @@ describe('useSecureDataAccess', () => {
394
426
  });
395
427
 
396
428
  it('handles organisation access validation failures', async () => {
397
- mockUseOrganisations.mockReturnValue({
398
- selectedOrganisation: mockSelectedOrganisation,
399
- getUserRole: vi.fn().mockReturnValue('no_access'),
400
- validateOrganisationAccess: vi.fn().mockResolvedValue(false),
401
- // Add other required properties
402
- } as any);
429
+ // Mock useResolvedScope to return null scope to simulate missing context
430
+ mockUseResolvedScope.mockReturnValue({
431
+ resolvedScope: null,
432
+ isLoading: false,
433
+ error: null,
434
+ });
403
435
 
404
436
  const { result } = renderHook(() => useSecureDataAccess());
405
437
 
406
- await expect(result.current.secureQuery('users', '*')).rejects.toThrow();
438
+ await expect(result.current.secureQuery('users', '*')).rejects.toThrow('Organisation context is required for data access');
407
439
  });
408
440
  });
409
441
 
@@ -411,7 +443,7 @@ describe('useSecureDataAccess', () => {
411
443
  it('prevents data leaks between organisations', async () => {
412
444
  const { result } = renderHook(() => useSecureDataAccess());
413
445
 
414
- await result.current.secureQuery('event', '*');
446
+ await result.current.secureQuery('core_events', '*');
415
447
 
416
448
  // Verify organisation_id filter is always applied
417
449
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -467,13 +499,25 @@ describe('useSecureDataAccess', () => {
467
499
 
468
500
  // Change organisation
469
501
  const newOrganisation = { id: 'org-456', name: 'New Organisation' };
470
- mockUseOrganisations.mockReturnValue({
502
+ mockUseUnifiedAuth.mockReturnValue({
503
+ user: mockUser,
504
+ session: mockSession,
505
+ supabase: freshMockSupabase,
506
+ isAuthenticated: true,
507
+ signOut: vi.fn(),
471
508
  selectedOrganisation: newOrganisation,
472
- getUserRole: vi.fn().mockReturnValue('member'),
473
- validateOrganisationAccess: vi.fn().mockResolvedValue(true),
474
- ensureOrganisationContext: vi.fn().mockReturnValue(newOrganisation),
475
- // Add other required properties
476
509
  } as any);
510
+
511
+ // Update useResolvedScope mock to return new organisation
512
+ mockUseResolvedScope.mockReturnValue({
513
+ resolvedScope: {
514
+ organisationId: 'org-456',
515
+ eventId: undefined,
516
+ appId: undefined,
517
+ },
518
+ isLoading: false,
519
+ error: null,
520
+ });
477
521
 
478
522
  rerender();
479
523
 
@@ -487,9 +531,10 @@ describe('useSecureDataAccess', () => {
487
531
  expect(mockUseUnifiedAuth).toHaveBeenCalled();
488
532
  });
489
533
 
490
- it('integrates with useOrganisations hook correctly', () => {
534
+ it('integrates with useResolvedScope hook correctly', () => {
491
535
  renderHook(() => useSecureDataAccess());
492
- expect(mockUseOrganisations).toHaveBeenCalled();
536
+ // useSecureDataAccess now uses useResolvedScope instead of useOrganisations
537
+ expect(mockUseResolvedScope).toHaveBeenCalled();
493
538
  });
494
539
 
495
540
  it('uses organisation context from provider', () => {