@jmruthers/pace-core 0.5.190 → 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 (249) hide show
  1. package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
  2. package/dist/{DataTable-ON3IXISJ.js → DataTable-WKRZD47S.js} +6 -6
  3. package/dist/{PublicPageProvider-C4uxosp6.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +1 -1
  4. package/dist/{UnifiedAuthProvider-X5NXANVI.js → UnifiedAuthProvider-FTSG5XH7.js} +3 -3
  5. package/dist/{api-I6UCQ5S6.js → api-IHKALJZD.js} +2 -2
  6. package/dist/{chunk-J2XXC7R5.js → chunk-6LTQQAT6.js} +77 -111
  7. package/dist/chunk-6LTQQAT6.js.map +1 -0
  8. package/dist/{chunk-STYK4OH2.js → chunk-6TQDD426.js} +10 -10
  9. package/dist/chunk-6TQDD426.js.map +1 -0
  10. package/dist/{chunk-DZWK57KZ.js → chunk-G37KK66H.js} +1 -1
  11. package/dist/{chunk-DZWK57KZ.js.map → chunk-G37KK66H.js.map} +1 -1
  12. package/dist/{chunk-73HSNNOQ.js → chunk-LOMZXPSN.js} +13 -13
  13. package/dist/{chunk-Y4BUBBHD.js → chunk-OETXORNB.js} +3 -3
  14. package/dist/{chunk-RUYZKXOD.js → chunk-ROXMHMY2.js} +5 -3
  15. package/dist/chunk-ROXMHMY2.js.map +1 -0
  16. package/dist/{chunk-SDMHPX3X.js → chunk-ULHIJK66.js} +56 -21
  17. package/dist/{chunk-SDMHPX3X.js.map → chunk-ULHIJK66.js.map} +1 -1
  18. package/dist/{chunk-VVBAW5A5.js → chunk-VKB2CO4Z.js} +46 -35
  19. package/dist/chunk-VKB2CO4Z.js.map +1 -0
  20. package/dist/{chunk-HQVPB5MZ.js → chunk-VRGWKHDB.js} +6 -6
  21. package/dist/{chunk-NIU6J6OX.js → chunk-XNYQOL3Z.js} +16 -16
  22. package/dist/chunk-XNYQOL3Z.js.map +1 -0
  23. package/dist/{chunk-4QYC5L4K.js → chunk-XYXSXPUK.js} +22 -27
  24. package/dist/chunk-XYXSXPUK.js.map +1 -0
  25. package/dist/components.d.ts +3 -3
  26. package/dist/components.js +8 -8
  27. package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
  28. package/dist/hooks.d.ts +12 -12
  29. package/dist/hooks.js +7 -7
  30. package/dist/index.d.ts +7 -7
  31. package/dist/index.js +18 -23
  32. package/dist/index.js.map +1 -1
  33. package/dist/providers.js +2 -2
  34. package/dist/rbac/index.d.ts +1 -1
  35. package/dist/rbac/index.js +6 -6
  36. package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
  37. package/dist/types.d.ts +2 -2
  38. package/dist/{usePublicRouteParams-DxIDS4bC.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +1 -1
  39. package/dist/utils.d.ts +8 -8
  40. package/dist/utils.js +2 -2
  41. package/docs/api/classes/ColumnFactory.md +1 -1
  42. package/docs/api/classes/ErrorBoundary.md +1 -1
  43. package/docs/api/classes/InvalidScopeError.md +1 -1
  44. package/docs/api/classes/Logger.md +1 -1
  45. package/docs/api/classes/MissingUserContextError.md +1 -1
  46. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  47. package/docs/api/classes/PermissionDeniedError.md +1 -1
  48. package/docs/api/classes/RBACAuditManager.md +2 -2
  49. package/docs/api/classes/RBACCache.md +1 -1
  50. package/docs/api/classes/RBACEngine.md +2 -2
  51. package/docs/api/classes/RBACError.md +1 -1
  52. package/docs/api/classes/RBACNotInitializedError.md +1 -1
  53. package/docs/api/classes/SecureSupabaseClient.md +5 -5
  54. package/docs/api/classes/StorageUtils.md +1 -1
  55. package/docs/api/enums/FileCategory.md +1 -1
  56. package/docs/api/enums/LogLevel.md +1 -1
  57. package/docs/api/enums/RBACErrorCode.md +1 -1
  58. package/docs/api/enums/RPCFunction.md +1 -1
  59. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  60. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  61. package/docs/api/interfaces/AggregateConfig.md +1 -1
  62. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  63. package/docs/api/interfaces/AvatarProps.md +1 -1
  64. package/docs/api/interfaces/BadgeProps.md +1 -1
  65. package/docs/api/interfaces/ButtonProps.md +1 -1
  66. package/docs/api/interfaces/CalendarProps.md +1 -1
  67. package/docs/api/interfaces/CardProps.md +1 -1
  68. package/docs/api/interfaces/ColorPalette.md +1 -1
  69. package/docs/api/interfaces/ColorShade.md +1 -1
  70. package/docs/api/interfaces/ComplianceResult.md +1 -1
  71. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  72. package/docs/api/interfaces/DataRecord.md +1 -1
  73. package/docs/api/interfaces/DataTableAction.md +1 -1
  74. package/docs/api/interfaces/DataTableColumn.md +1 -1
  75. package/docs/api/interfaces/DataTableProps.md +1 -1
  76. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  77. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  78. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  79. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  80. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  81. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  82. package/docs/api/interfaces/ExportColumn.md +1 -1
  83. package/docs/api/interfaces/ExportOptions.md +1 -1
  84. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  85. package/docs/api/interfaces/FileMetadata.md +1 -1
  86. package/docs/api/interfaces/FileReference.md +1 -1
  87. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  88. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  89. package/docs/api/interfaces/FileUploadProps.md +1 -1
  90. package/docs/api/interfaces/FooterProps.md +1 -1
  91. package/docs/api/interfaces/FormFieldProps.md +1 -1
  92. package/docs/api/interfaces/FormProps.md +1 -1
  93. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  94. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  95. package/docs/api/interfaces/InputProps.md +1 -1
  96. package/docs/api/interfaces/LabelProps.md +1 -1
  97. package/docs/api/interfaces/LoggerConfig.md +1 -1
  98. package/docs/api/interfaces/LoginFormProps.md +1 -1
  99. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  100. package/docs/api/interfaces/NavigationContextType.md +1 -1
  101. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  102. package/docs/api/interfaces/NavigationItem.md +1 -1
  103. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  104. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  105. package/docs/api/interfaces/Organisation.md +1 -1
  106. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  107. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  108. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  109. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  110. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  111. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  112. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  113. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  114. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  115. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  116. package/docs/api/interfaces/PaletteData.md +1 -1
  117. package/docs/api/interfaces/ParsedAddress.md +2 -2
  118. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  119. package/docs/api/interfaces/ProgressProps.md +1 -1
  120. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  121. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  122. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  123. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  124. package/docs/api/interfaces/QuickFix.md +1 -1
  125. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  126. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  127. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  128. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  129. package/docs/api/interfaces/RBACConfig.md +2 -2
  130. package/docs/api/interfaces/RBACContext.md +1 -1
  131. package/docs/api/interfaces/RBACLogger.md +1 -1
  132. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  133. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  134. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  135. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  136. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  137. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  138. package/docs/api/interfaces/RBACResult.md +1 -1
  139. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  140. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  141. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  142. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  143. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  144. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  145. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  146. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  147. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  148. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  149. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  150. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  151. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  152. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  153. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  154. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  155. package/docs/api/interfaces/RouteConfig.md +1 -1
  156. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  157. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  158. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  159. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  160. package/docs/api/interfaces/SetupIssue.md +1 -1
  161. package/docs/api/interfaces/StorageConfig.md +1 -1
  162. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  163. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  164. package/docs/api/interfaces/StorageListOptions.md +1 -1
  165. package/docs/api/interfaces/StorageListResult.md +1 -1
  166. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  167. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  168. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  169. package/docs/api/interfaces/StyleImport.md +1 -1
  170. package/docs/api/interfaces/SwitchProps.md +1 -1
  171. package/docs/api/interfaces/TabsContentProps.md +1 -1
  172. package/docs/api/interfaces/TabsListProps.md +1 -1
  173. package/docs/api/interfaces/TabsProps.md +1 -1
  174. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  175. package/docs/api/interfaces/TextareaProps.md +1 -1
  176. package/docs/api/interfaces/ToastActionElement.md +1 -1
  177. package/docs/api/interfaces/ToastProps.md +1 -1
  178. package/docs/api/interfaces/UnifiedAuthContextType.md +1 -1
  179. package/docs/api/interfaces/UnifiedAuthProviderProps.md +1 -1
  180. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  181. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  182. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  183. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  184. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  185. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  186. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  187. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  188. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  189. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  190. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  191. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  192. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  193. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  194. package/docs/api/interfaces/UserEventAccess.md +1 -1
  195. package/docs/api/interfaces/UserMenuProps.md +1 -1
  196. package/docs/api/interfaces/UserProfile.md +1 -1
  197. package/docs/api/modules.md +16 -16
  198. package/docs/migration/README.md +18 -0
  199. package/docs/migration/database-changes-december-2025.md +767 -0
  200. package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
  201. package/package.json +1 -1
  202. package/src/__tests__/public-recipe-view.test.ts +10 -10
  203. package/src/__tests__/rls-policies.test.ts +13 -13
  204. package/src/components/AddressField/README.md +6 -6
  205. package/src/components/OrganisationSelector/OrganisationSelector.tsx +35 -15
  206. package/src/components/Select/Select.test.tsx +4 -1
  207. package/src/components/Select/Select.tsx +60 -15
  208. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +192 -0
  209. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +741 -0
  210. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +703 -0
  211. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +581 -0
  212. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +9 -8
  213. package/src/hooks/public/usePublicEvent.ts +8 -8
  214. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  215. package/src/hooks/useFileDisplay.ts +8 -9
  216. package/src/hooks/useQueryCache.ts +6 -6
  217. package/src/hooks/useSecureDataAccess.test.ts +8 -8
  218. package/src/hooks/useSecureDataAccess.ts +15 -11
  219. package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
  220. package/src/rbac/hooks/useRBAC.simple.test.ts +95 -0
  221. package/src/rbac/utils/__tests__/eventContext.test.ts +2 -2
  222. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +490 -0
  223. package/src/rbac/utils/eventContext.ts +5 -2
  224. package/src/services/AuthService.ts +37 -8
  225. package/src/services/OrganisationService.ts +92 -139
  226. package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
  227. package/src/services/__tests__/OrganisationService.test.ts +218 -86
  228. package/src/types/database.generated.ts +166 -201
  229. package/src/types/supabase.ts +2 -2
  230. package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
  231. package/src/utils/file-reference/index.ts +4 -4
  232. package/src/utils/google-places/googlePlacesUtils.ts +1 -1
  233. package/src/utils/google-places/types.ts +1 -1
  234. package/src/utils/request-deduplication.ts +4 -4
  235. package/src/utils/security/secureDataAccess.test.ts +1 -1
  236. package/src/utils/security/secureDataAccess.ts +7 -4
  237. package/src/utils/storage/README.md +1 -1
  238. package/dist/chunk-4QYC5L4K.js.map +0 -1
  239. package/dist/chunk-J2XXC7R5.js.map +0 -1
  240. package/dist/chunk-NIU6J6OX.js.map +0 -1
  241. package/dist/chunk-RUYZKXOD.js.map +0 -1
  242. package/dist/chunk-STYK4OH2.js.map +0 -1
  243. package/dist/chunk-VVBAW5A5.js.map +0 -1
  244. /package/dist/{DataTable-ON3IXISJ.js.map → DataTable-WKRZD47S.js.map} +0 -0
  245. /package/dist/{UnifiedAuthProvider-X5NXANVI.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
  246. /package/dist/{api-I6UCQ5S6.js.map → api-IHKALJZD.js.map} +0 -0
  247. /package/dist/{chunk-73HSNNOQ.js.map → chunk-LOMZXPSN.js.map} +0 -0
  248. /package/dist/{chunk-Y4BUBBHD.js.map → chunk-OETXORNB.js.map} +0 -0
  249. /package/dist/{chunk-HQVPB5MZ.js.map → chunk-VRGWKHDB.js.map} +0 -0
@@ -202,7 +202,7 @@ export function usePublicFileDisplay(
202
202
  const ids = userData.map((item: any) => item.id);
203
203
  if (ids.length > 0) {
204
204
  const { data: fullData } = await supabase
205
- .from('file_references')
205
+ .from('core_file_references')
206
206
  .select('id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at')
207
207
  .in('id', ids)
208
208
  .eq('is_public', true);
@@ -320,7 +320,7 @@ export function usePublicFileDisplay(
320
320
  // Fetch full file reference data for each ID, but only public files
321
321
  const ids = fileIds.map((item: any) => item.id);
322
322
  const { data: fullData, error: fetchError } = await supabase
323
- .from('file_references')
323
+ .from('core_file_references')
324
324
  .select('id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at')
325
325
  .in('id', ids)
326
326
  .eq('is_public', true); // Only public files in public context
@@ -4,7 +4,7 @@
4
4
  * @module Hooks
5
5
  *
6
6
  * A React hook for accessing file references in authenticated contexts.
7
- * Can handle both public and private files using the file_references system.
7
+ * Can handle both public and private files using the core_file_references system.
8
8
  *
9
9
  * Features:
10
10
  * - Works in authenticated contexts
@@ -20,7 +20,7 @@
20
20
  *
21
21
  * function FileView() {
22
22
  * const { fileUrl, fileReference, isLoading, error } = useFileDisplay(
23
- * 'event',
23
+ * 'core_events',
24
24
  * eventId,
25
25
  * organisationId,
26
26
  * FileCategory.EVENT_LOGOS
@@ -247,10 +247,9 @@ export function useFileDisplay(
247
247
  if (user) {
248
248
  // Query user's active organisation memberships
249
249
  const { data: memberships, error: membershipError } = await supabase
250
- .from('organisation_memberships')
250
+ .from('core_organisation_memberships')
251
251
  .select('organisation_id')
252
- .eq('user_id', user.id)
253
- .or('status.is.null,status.eq.active');
252
+ .eq('user_id', user.id);
254
253
 
255
254
  if (membershipError) {
256
255
  logger.warn('useFileDisplay', 'Error querying organisation memberships:', membershipError);
@@ -292,7 +291,7 @@ export function useFileDisplay(
292
291
  try {
293
292
  // Try querying without organisation_id filter - let RLS handle security
294
293
  let fallbackQuery = supabase
295
- .from('file_references')
294
+ .from('core_file_references')
296
295
  .select('id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at')
297
296
  .eq('table_name', table_name)
298
297
  .eq('record_id', record_id)
@@ -350,11 +349,11 @@ export function useFileDisplay(
350
349
 
351
350
  // If no files found through RPC, try a direct query as fallback
352
351
  // This handles cases where RLS policy allows access but RPC security check is too strict
353
- // (e.g., pace_person files where user owns the person record but record_id != user_id)
352
+ // (e.g., core_person files where user owns the person record but record_id != user_id)
354
353
  if (files.length === 0) {
355
354
  try {
356
355
  let directQuery = supabase
357
- .from('file_references')
356
+ .from('core_file_references')
358
357
  .select('id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at')
359
358
  .eq('table_name', table_name)
360
359
  .eq('record_id', record_id)
@@ -444,7 +443,7 @@ export function useFileDisplay(
444
443
  const { data: { user } } = await supabase.auth.getUser();
445
444
  if (user) {
446
445
  const { data: memberships } = await supabase
447
- .from('organisation_memberships')
446
+ .from('core_organisation_memberships')
448
447
  .select('organisation_id')
449
448
  .eq('user_id', user.id)
450
449
  .or('status.is.null,status.eq.active');
@@ -112,12 +112,12 @@ export interface UseQueryCacheReturn {
112
112
  * const { getCachedQuery } = useQueryCache(supabase);
113
113
  *
114
114
  * const person = await getCachedQuery(
115
- * 'pace_person',
115
+ * 'core_person',
116
116
  * 'user_id',
117
117
  * userId,
118
118
  * async () => {
119
119
  * const { data } = await supabase
120
- * .from('pace_person')
120
+ * .from('core_person')
121
121
  * .select('id, first_name, last_name, email')
122
122
  * .eq('user_id', userId)
123
123
  * .single();
@@ -220,7 +220,7 @@ export function useQueryCache(supabase?: SupabaseClient<Database>): UseQueryCach
220
220
  */
221
221
  export const queryCacheHelpers = {
222
222
  /**
223
- * Cache pace_person queries by user_id
223
+ * Cache core_person queries by user_id
224
224
  * TTL: 5 minutes
225
225
  */
226
226
  pacePersonByUserId: <T>(
@@ -228,7 +228,7 @@ export const queryCacheHelpers = {
228
228
  userId: string,
229
229
  fetchFn: () => Promise<T>
230
230
  ): Promise<T> => {
231
- const cacheKey = `pace_person:user_id:${userId}`;
231
+ const cacheKey = `core_person:user_id:${userId}`;
232
232
  const now = Date.now();
233
233
  const ttl = 300 * 1000; // 5 minutes
234
234
 
@@ -258,7 +258,7 @@ export const queryCacheHelpers = {
258
258
  },
259
259
 
260
260
  /**
261
- * Cache pace_member queries by person_id
261
+ * Cache core_member queries by person_id
262
262
  * TTL: 5 minutes
263
263
  */
264
264
  paceMemberByPersonId: <T>(
@@ -266,7 +266,7 @@ export const queryCacheHelpers = {
266
266
  personId: string,
267
267
  fetchFn: () => Promise<T>
268
268
  ): Promise<T> => {
269
- const cacheKey = `pace_member:person_id:${personId}`;
269
+ const cacheKey = `core_member:person_id:${personId}`;
270
270
  const now = Date.now();
271
271
  const ttl = 300 * 1000; // 5 minutes
272
272
 
@@ -154,9 +154,9 @@ describe('useSecureDataAccess', () => {
154
154
  it('executes secure query with organisation filtering', async () => {
155
155
  const { result } = renderHook(() => useSecureDataAccess());
156
156
 
157
- const data = await result.current.secureQuery('event', '*', { active: true });
157
+ const data = await result.current.secureQuery('core_events', '*', { active: true });
158
158
 
159
- expect(freshMockSupabase.from).toHaveBeenCalledWith('event');
159
+ expect(freshMockSupabase.from).toHaveBeenCalledWith('core_events');
160
160
  expect(freshMockQueryBuilder.select).toHaveBeenCalledWith('*');
161
161
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
162
162
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('active', true);
@@ -270,9 +270,9 @@ describe('useSecureDataAccess', () => {
270
270
  it('executes secure update with organisation filtering', async () => {
271
271
  const { result } = renderHook(() => useSecureDataAccess());
272
272
 
273
- 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' });
274
274
 
275
- expect(freshMockSupabase.from).toHaveBeenCalledWith('event');
275
+ expect(freshMockSupabase.from).toHaveBeenCalledWith('core_events');
276
276
  expect(freshMockQueryBuilder.update).toHaveBeenCalledWith({ event_name: 'Updated Event' });
277
277
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('id', 'event-123');
278
278
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -307,9 +307,9 @@ describe('useSecureDataAccess', () => {
307
307
  it('executes secure delete with organisation filtering', async () => {
308
308
  const { result } = renderHook(() => useSecureDataAccess());
309
309
 
310
- await result.current.secureDelete('event', { id: 'event-123' });
310
+ await result.current.secureDelete('core_events', { id: 'event-123' });
311
311
 
312
- expect(freshMockSupabase.from).toHaveBeenCalledWith('event');
312
+ expect(freshMockSupabase.from).toHaveBeenCalledWith('core_events');
313
313
  expect(freshMockQueryBuilder.delete).toHaveBeenCalled();
314
314
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('id', 'event-123');
315
315
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -387,7 +387,7 @@ describe('useSecureDataAccess', () => {
387
387
  const { result } = renderHook(() => useSecureDataAccess());
388
388
 
389
389
  // Use 'event' table which is in the tablesWithOrganisation list
390
- await result.current.secureQuery('event', '*');
390
+ await result.current.secureQuery('core_events', '*');
391
391
 
392
392
  // Verify that the query was executed with organisation filter
393
393
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -443,7 +443,7 @@ describe('useSecureDataAccess', () => {
443
443
  it('prevents data leaks between organisations', async () => {
444
444
  const { result } = renderHook(() => useSecureDataAccess());
445
445
 
446
- await result.current.secureQuery('event', '*');
446
+ await result.current.secureQuery('core_events', '*');
447
447
 
448
448
  // Verify organisation_id filter is always applied
449
449
  expect(freshMockQueryBuilder.eq).toHaveBeenCalledWith('organisation_id', 'org-123');
@@ -15,7 +15,7 @@
15
15
  * const loadData = async () => {
16
16
  * try {
17
17
  * // Automatically includes organisation_id filter
18
- * const events = await secureQuery('event', '*', { is_visible: true });
18
+ * const events = await secureQuery('core_events', '*', { is_visible: true });
19
19
  * console.log('Organisation events:', events);
20
20
  * } catch (error) {
21
21
  * console.error('Failed to load data:', error);
@@ -25,7 +25,7 @@
25
25
  * const createEvent = async (eventData) => {
26
26
  * try {
27
27
  * // Automatically sets organisation_id
28
- * const newEvent = await secureInsert('event', eventData);
28
+ * const newEvent = await secureInsert('core_events', eventData);
29
29
  * console.log('Created event:', newEvent);
30
30
  * } catch (error) {
31
31
  * console.error('Failed to create event:', error);
@@ -231,15 +231,19 @@ export function useSecureDataAccess(): SecureDataAccessReturn {
231
231
  // - RLS policies are the primary security layer (cannot be bypassed)
232
232
  // - Application-level filtering adds an additional layer of protection
233
233
  const tablesWithOrganisation = [
234
- 'event', 'organisation_settings',
234
+ 'core_events', 'organisation_settings',
235
235
  'rbac_event_app_roles', 'rbac_organisation_roles',
236
236
  // SECURITY: Phase 2 additions - complete organisation table mapping
237
237
  'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',
238
238
  // SECURITY: Emergency additions for Phase 1 fixes
239
- 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',
239
+ 'cake_meal', 'cake_mealtype', 'core_person',
240
+ // NOTE: core_member, medi_profile, core_contact, core_consent, core_identification, core_qualification
241
+ // are now person-scoped (not organisation-scoped) - removed from this list
240
242
  // SECURITY: Phase 3A additions - medical and personal data
241
- 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',
242
- 'pace_consent', 'pace_contact', 'pace_identification', 'pace_identification_type', 'pace_qualification',
243
+ // NOTE: medi_condition, medi_diet, medi_action_plan, medi_profile_versions are now person-scoped
244
+ // (via medi_profile) - removed from this list
245
+ // core_identification_type remains organisation-scoped (lookup table)
246
+ 'core_identification_type',
243
247
  'form_responses', 'form_response_values', 'forms',
244
248
  // SECURITY: Phase 3B additions - remaining critical tables
245
249
  'invoice', 'line_item', 'credit_balance', 'payment_method',
@@ -360,12 +364,12 @@ export function useSecureDataAccess(): SecureDataAccessReturn {
360
364
 
361
365
  // Add organisation filter only if table has organisation_id column
362
366
  const tablesWithOrganisation = [
363
- 'event', 'organisation_settings',
367
+ 'core_events', 'organisation_settings',
364
368
  'rbac_event_app_roles', 'rbac_organisation_roles',
365
369
  // SECURITY: Phase 2 additions - complete organisation table mapping
366
370
  'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',
367
371
  // SECURITY: Emergency additions for Phase 1 fixes
368
- 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member'
372
+ 'cake_meal', 'cake_mealtype', 'core_person', 'core_member'
369
373
  ];
370
374
 
371
375
  if (!bypassOrganisationFilter && organisationId && tablesWithOrganisation.includes(table)) {
@@ -407,15 +411,15 @@ export function useSecureDataAccess(): SecureDataAccessReturn {
407
411
 
408
412
  // Add organisation filter only if table has organisation_id column
409
413
  const tablesWithOrganisation = [
410
- 'event', 'organisation_settings',
414
+ 'core_events', 'organisation_settings',
411
415
  'rbac_event_app_roles', 'rbac_organisation_roles',
412
416
  // SECURITY: Phase 2 additions - complete organisation table mapping
413
417
  'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',
414
418
  // SECURITY: Emergency additions for Phase 1 fixes
415
- 'cake_meal', 'cake_mealtype', 'pace_person', 'pace_member',
419
+ 'cake_meal', 'cake_mealtype', 'core_person', 'core_member',
416
420
  // SECURITY: Phase 3A additions - medical and personal data
417
421
  'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',
418
- 'pace_consent', 'pace_contact', 'pace_identification', 'pace_identification_type', 'pace_qualification',
422
+ 'core_consent', 'core_contact', 'core_identification', 'core_identification_type', 'core_qualification',
419
423
  'form_responses', 'form_response_values', 'forms',
420
424
  // SECURITY: Phase 3B additions - remaining critical tables
421
425
  'invoice', 'line_item', 'credit_balance', 'payment_method',
@@ -40,24 +40,7 @@ const createMockSupabaseClient = () => {
40
40
  const orgId = '123e4567-e89b-12d3-a456-426614174000'; // Valid UUID format
41
41
  const userId = '123e4567-e89b-12d3-a456-426614174001'; // Valid UUID format
42
42
 
43
- return {
44
- rpc: vi.fn().mockResolvedValue({
45
- data: [
46
- {
47
- user_id: userId,
48
- organisation_id: orgId,
49
- role: 'org_admin',
50
- status: 'active',
51
- },
52
- ],
53
- error: null,
54
- }),
55
- from: vi.fn((table: string) => {
56
- if (table === 'organisations') {
57
- return {
58
- select: vi.fn().mockResolvedValue({
59
- data: [
60
- {
43
+ const mockOrganisation = {
61
44
  id: orgId,
62
45
  name: 'Test Organisation 1',
63
46
  display_name: 'Test Organisation 1',
@@ -67,11 +50,34 @@ const createMockSupabaseClient = () => {
67
50
  parent_id: null,
68
51
  created_at: '2023-01-01T00:00:00Z',
69
52
  updated_at: '2023-01-01T00:00:00Z',
70
- },
71
- ],
53
+ };
54
+
55
+ const mockQueryBuilder = {
56
+ select: vi.fn().mockReturnThis(),
57
+ eq: vi.fn().mockReturnThis(),
58
+ is: vi.fn().mockResolvedValue({
59
+ data: [{
60
+ id: 'membership-1',
61
+ user_id: userId,
62
+ organisation_id: orgId,
63
+ role: 'org_admin',
64
+ status: 'active',
65
+ granted_at: '2023-01-01T00:00:00Z',
66
+ revoked_at: null,
67
+ core_organisations: mockOrganisation
68
+ }],
69
+ error: null
70
+ })
71
+ };
72
+
73
+ return {
74
+ rpc: vi.fn().mockResolvedValue({
75
+ data: [],
72
76
  error: null,
73
77
  }),
74
- };
78
+ from: vi.fn((table: string) => {
79
+ if (table === 'rbac_organisation_roles') {
80
+ return mockQueryBuilder;
75
81
  }
76
82
  return {
77
83
  select: vi.fn().mockResolvedValue({ data: [], error: null }),
@@ -0,0 +1,95 @@
1
+ /**
2
+ * @file useRBAC Hook Simple Tests
3
+ * @package @jmruthers/pace-core
4
+ * @module RBAC/Hooks/useRBAC
5
+ * @since 0.3.0
6
+ *
7
+ * Simple tests for the useRBAC hook to verify basic functionality.
8
+ */
9
+
10
+ import { renderHook } from '@testing-library/react';
11
+ import { vi, describe, it, expect, beforeEach } from 'vitest';
12
+
13
+ // Mock the providers with simple mocks
14
+ vi.mock('../../providers/UnifiedAuthProvider', () => ({
15
+ useUnifiedAuth: vi.fn(() => ({
16
+ user: { id: 'user-123' },
17
+ session: { access_token: 'mock-token' },
18
+ supabase: {
19
+ // Ensure realtime init is skipped
20
+ channel: undefined,
21
+ from: vi.fn(() => ({
22
+ select: vi.fn(() => ({
23
+ eq: vi.fn(() => ({
24
+ eq: vi.fn(() => ({
25
+ single: vi.fn().mockResolvedValue({
26
+ data: { global_role: 'user' },
27
+ error: null
28
+ })
29
+ }))
30
+ }))
31
+ }))
32
+ }))
33
+ },
34
+ appName: 'test-app'
35
+ }))
36
+ }));
37
+
38
+ vi.mock('../../providers/OrganisationProvider', () => ({
39
+ useOrganisations: vi.fn(() => ({
40
+ selectedOrganisation: { id: 'org-123', name: 'Test Org' }
41
+ }))
42
+ }));
43
+
44
+ vi.mock('../../providers/EventProvider', () => ({
45
+ useEvents: vi.fn(() => ({
46
+ selectedEvent: { event_id: 'event-123', name: 'Test Event' }
47
+ }))
48
+ }));
49
+
50
+ // Import after mocking
51
+ vi.mock('./useRBAC', () => ({
52
+ useRBAC: () => ({
53
+ isLoading: false,
54
+ isAuthenticated: true,
55
+ globalRole: 'user',
56
+ organisationRole: 'member',
57
+ eventAppRole: 'participant',
58
+ isSuperAdmin: false,
59
+ isOrgAdmin: false,
60
+ hasGlobalPermission: () => true,
61
+ error: null,
62
+ }),
63
+ }));
64
+ import { useRBAC } from './useRBAC';
65
+
66
+ describe('useRBAC Hook - Simple Tests', () => {
67
+ it('renders without crashing', () => {
68
+ const { result } = renderHook(() => useRBAC());
69
+
70
+ expect(result.current).toBeDefined();
71
+ expect(result.current.globalRole).toBeDefined();
72
+ expect(result.current.organisationRole).toBeDefined();
73
+ expect(result.current.eventAppRole).toBeDefined();
74
+ });
75
+
76
+ it('has required properties', () => {
77
+ const { result } = renderHook(() => useRBAC());
78
+
79
+ expect(result.current).toHaveProperty('globalRole');
80
+ expect(result.current).toHaveProperty('organisationRole');
81
+ expect(result.current).toHaveProperty('eventAppRole');
82
+ expect(result.current).toHaveProperty('hasGlobalPermission');
83
+ expect(result.current).toHaveProperty('isSuperAdmin');
84
+ expect(result.current).toHaveProperty('isOrgAdmin');
85
+ expect(result.current).toHaveProperty('isLoading');
86
+ expect(result.current).toHaveProperty('error');
87
+ // Note: hasPermission was removed - use useCan() hook instead
88
+ });
89
+
90
+ it('hasGlobalPermission is a function', () => {
91
+ const { result } = renderHook(() => useRBAC());
92
+
93
+ expect(typeof result.current.hasGlobalPermission).toBe('function');
94
+ });
95
+ });
@@ -41,7 +41,7 @@ describe('Event Context Utilities', () => {
41
41
  // Clear cache before each test to prevent test interference
42
42
  clearAllOrgDerivationCache();
43
43
  mockSupabase = createMockSupabaseClient();
44
- mockQuery = mockSupabase.from('event');
44
+ mockQuery = mockSupabase.from('core_events');
45
45
  });
46
46
 
47
47
  afterEach(() => {
@@ -63,7 +63,7 @@ describe('Event Context Utilities', () => {
63
63
  const result = await getOrganisationFromEvent(mockSupabase, eventId);
64
64
 
65
65
  expect(result).toBe(organisationId);
66
- expect(mockSupabase.from).toHaveBeenCalledWith('event');
66
+ expect(mockSupabase.from).toHaveBeenCalledWith('core_events');
67
67
  expect(mockQuery.select).toHaveBeenCalledWith('organisation_id');
68
68
  expect(mockQuery.eq).toHaveBeenCalledWith('event_id', eventId);
69
69
  expect(mockQuery.single).toHaveBeenCalled();