@jmruthers/pace-core 0.5.189 → 0.5.190

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 (420) 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-GUFUNZ3N.js → DataTable-ON3IXISJ.js} +8 -8
  4. package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-C4uxosp6.d.ts} +83 -24
  5. package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
  6. package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-X5NXANVI.js} +4 -2
  7. package/dist/{api-YP7XD5L6.js → api-I6UCQ5S6.js} +4 -2
  8. package/dist/{chunk-DDM4CCYT.js → chunk-4QYC5L4K.js} +60 -35
  9. package/dist/chunk-4QYC5L4K.js.map +1 -0
  10. package/dist/{chunk-IM4QE42D.js → chunk-73HSNNOQ.js} +141 -326
  11. package/dist/chunk-73HSNNOQ.js.map +1 -0
  12. package/dist/{chunk-YHCN776L.js → chunk-DZWK57KZ.js} +2 -75
  13. package/dist/chunk-DZWK57KZ.js.map +1 -0
  14. package/dist/{chunk-3GOZZZYH.js → chunk-HQVPB5MZ.js} +238 -301
  15. package/dist/chunk-HQVPB5MZ.js.map +1 -0
  16. package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
  17. package/dist/chunk-HW3OVDUF.js.map +1 -0
  18. package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
  19. package/dist/chunk-I7PSE6JW.js.map +1 -0
  20. package/dist/{chunk-VGZZXKBR.js → chunk-J2XXC7R5.js} +280 -52
  21. package/dist/chunk-J2XXC7R5.js.map +1 -0
  22. package/dist/{chunk-UCQSRW7Z.js → chunk-NIU6J6OX.js} +425 -378
  23. package/dist/chunk-NIU6J6OX.js.map +1 -0
  24. package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
  25. package/dist/{chunk-HEHYGYOX.js → chunk-RUYZKXOD.js} +401 -46
  26. package/dist/chunk-RUYZKXOD.js.map +1 -0
  27. package/dist/{chunk-2UUZZJFT.js → chunk-SDMHPX3X.js} +176 -160
  28. package/dist/{chunk-2UUZZJFT.js.map → chunk-SDMHPX3X.js.map} +1 -1
  29. package/dist/{chunk-MX64ZF6I.js → chunk-STYK4OH2.js} +11 -11
  30. package/dist/chunk-STYK4OH2.js.map +1 -0
  31. package/dist/{chunk-YGPFYGA6.js → chunk-VVBAW5A5.js} +822 -498
  32. package/dist/chunk-VVBAW5A5.js.map +1 -0
  33. package/dist/chunk-Y4BUBBHD.js +614 -0
  34. package/dist/chunk-Y4BUBBHD.js.map +1 -0
  35. package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
  36. package/dist/chunk-ZSAAAMVR.js.map +1 -0
  37. package/dist/components.d.ts +3 -4
  38. package/dist/components.js +19 -19
  39. package/dist/components.js.map +1 -1
  40. package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
  41. package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
  42. package/dist/hooks.d.ts +10 -5
  43. package/dist/hooks.js +14 -8
  44. package/dist/hooks.js.map +1 -1
  45. package/dist/index.d.ts +13 -11
  46. package/dist/index.js +79 -69
  47. package/dist/index.js.map +1 -1
  48. package/dist/providers.d.ts +3 -3
  49. package/dist/providers.js +3 -1
  50. package/dist/rbac/index.d.ts +76 -12
  51. package/dist/rbac/index.js +12 -9
  52. package/dist/types.d.ts +1 -1
  53. package/dist/types.js +1 -1
  54. package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-DxIDS4bC.d.ts} +16 -9
  55. package/dist/utils.js +16 -16
  56. package/docs/README.md +2 -2
  57. package/docs/api/classes/ColumnFactory.md +1 -1
  58. package/docs/api/classes/ErrorBoundary.md +1 -1
  59. package/docs/api/classes/InvalidScopeError.md +2 -2
  60. package/docs/api/classes/Logger.md +1 -1
  61. package/docs/api/classes/MissingUserContextError.md +2 -2
  62. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  63. package/docs/api/classes/PermissionDeniedError.md +1 -1
  64. package/docs/api/classes/RBACAuditManager.md +1 -1
  65. package/docs/api/classes/RBACCache.md +1 -1
  66. package/docs/api/classes/RBACEngine.md +4 -4
  67. package/docs/api/classes/RBACError.md +1 -1
  68. package/docs/api/classes/RBACNotInitializedError.md +2 -2
  69. package/docs/api/classes/SecureSupabaseClient.md +21 -16
  70. package/docs/api/classes/StorageUtils.md +7 -4
  71. package/docs/api/enums/FileCategory.md +1 -1
  72. package/docs/api/enums/LogLevel.md +1 -1
  73. package/docs/api/enums/RBACErrorCode.md +1 -1
  74. package/docs/api/enums/RPCFunction.md +1 -1
  75. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  76. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  77. package/docs/api/interfaces/AggregateConfig.md +1 -1
  78. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  79. package/docs/api/interfaces/AvatarProps.md +1 -1
  80. package/docs/api/interfaces/BadgeProps.md +1 -1
  81. package/docs/api/interfaces/ButtonProps.md +1 -1
  82. package/docs/api/interfaces/CalendarProps.md +20 -6
  83. package/docs/api/interfaces/CardProps.md +1 -1
  84. package/docs/api/interfaces/ColorPalette.md +1 -1
  85. package/docs/api/interfaces/ColorShade.md +1 -1
  86. package/docs/api/interfaces/ComplianceResult.md +1 -1
  87. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  88. package/docs/api/interfaces/DataRecord.md +1 -1
  89. package/docs/api/interfaces/DataTableAction.md +1 -1
  90. package/docs/api/interfaces/DataTableColumn.md +1 -1
  91. package/docs/api/interfaces/DataTableProps.md +1 -1
  92. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  93. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  94. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  95. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  96. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  97. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  98. package/docs/api/interfaces/ExportColumn.md +1 -1
  99. package/docs/api/interfaces/ExportOptions.md +1 -1
  100. package/docs/api/interfaces/FileDisplayProps.md +62 -16
  101. package/docs/api/interfaces/FileMetadata.md +1 -1
  102. package/docs/api/interfaces/FileReference.md +2 -2
  103. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  104. package/docs/api/interfaces/FileUploadOptions.md +26 -12
  105. package/docs/api/interfaces/FileUploadProps.md +30 -19
  106. package/docs/api/interfaces/FooterProps.md +1 -1
  107. package/docs/api/interfaces/FormFieldProps.md +1 -1
  108. package/docs/api/interfaces/FormProps.md +1 -1
  109. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  110. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  111. package/docs/api/interfaces/InputProps.md +1 -1
  112. package/docs/api/interfaces/LabelProps.md +1 -1
  113. package/docs/api/interfaces/LoggerConfig.md +1 -1
  114. package/docs/api/interfaces/LoginFormProps.md +1 -1
  115. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  116. package/docs/api/interfaces/NavigationContextType.md +9 -9
  117. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  118. package/docs/api/interfaces/NavigationItem.md +1 -1
  119. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  120. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  121. package/docs/api/interfaces/Organisation.md +1 -1
  122. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  123. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  124. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  125. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  126. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  127. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  128. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  129. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  130. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  131. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  132. package/docs/api/interfaces/PaletteData.md +1 -1
  133. package/docs/api/interfaces/ParsedAddress.md +1 -1
  134. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  135. package/docs/api/interfaces/ProgressProps.md +3 -11
  136. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  137. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  138. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  139. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  140. package/docs/api/interfaces/QuickFix.md +1 -1
  141. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  142. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  143. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  144. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  145. package/docs/api/interfaces/RBACConfig.md +1 -1
  146. package/docs/api/interfaces/RBACContext.md +1 -1
  147. package/docs/api/interfaces/RBACLogger.md +1 -1
  148. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  149. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  150. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  151. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  152. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  153. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  154. package/docs/api/interfaces/RBACResult.md +1 -1
  155. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  156. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  157. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  158. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  159. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  160. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  161. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  162. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  163. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  164. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  165. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  166. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  167. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  168. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  169. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  170. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  171. package/docs/api/interfaces/RouteConfig.md +10 -10
  172. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  173. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  174. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  175. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  176. package/docs/api/interfaces/SetupIssue.md +1 -1
  177. package/docs/api/interfaces/StorageConfig.md +4 -4
  178. package/docs/api/interfaces/StorageFileInfo.md +7 -7
  179. package/docs/api/interfaces/StorageFileMetadata.md +25 -14
  180. package/docs/api/interfaces/StorageListOptions.md +22 -9
  181. package/docs/api/interfaces/StorageListResult.md +4 -4
  182. package/docs/api/interfaces/StorageUploadOptions.md +21 -8
  183. package/docs/api/interfaces/StorageUploadResult.md +6 -6
  184. package/docs/api/interfaces/StorageUrlOptions.md +19 -6
  185. package/docs/api/interfaces/StyleImport.md +1 -1
  186. package/docs/api/interfaces/SwitchProps.md +1 -1
  187. package/docs/api/interfaces/TabsContentProps.md +1 -1
  188. package/docs/api/interfaces/TabsListProps.md +1 -1
  189. package/docs/api/interfaces/TabsProps.md +1 -1
  190. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  191. package/docs/api/interfaces/TextareaProps.md +1 -1
  192. package/docs/api/interfaces/ToastActionElement.md +1 -1
  193. package/docs/api/interfaces/ToastProps.md +1 -1
  194. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  195. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  196. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  197. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  198. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  199. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  200. package/docs/api/interfaces/UsePublicEventLogoOptions.md +1 -1
  201. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  202. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  203. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  204. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +1 -1
  205. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  206. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  207. package/docs/api/interfaces/UseResolvedScopeOptions.md +4 -4
  208. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  209. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  210. package/docs/api/interfaces/UserEventAccess.md +11 -11
  211. package/docs/api/interfaces/UserMenuProps.md +1 -1
  212. package/docs/api/interfaces/UserProfile.md +1 -1
  213. package/docs/api/modules.md +151 -92
  214. package/docs/api-reference/components.md +15 -7
  215. package/docs/api-reference/providers.md +2 -2
  216. package/docs/api-reference/rpc-functions.md +1 -0
  217. package/docs/best-practices/README.md +1 -1
  218. package/docs/best-practices/deployment.md +8 -8
  219. package/docs/getting-started/examples/README.md +2 -2
  220. package/docs/getting-started/installation-guide.md +4 -4
  221. package/docs/getting-started/quick-start.md +3 -3
  222. package/docs/migration/MIGRATION_GUIDE.md +3 -3
  223. package/docs/rbac/compliance/compliance-guide.md +2 -2
  224. package/docs/rbac/event-based-apps.md +2 -2
  225. package/docs/rbac/getting-started.md +2 -2
  226. package/docs/rbac/quick-start.md +2 -2
  227. package/docs/security/README.md +4 -4
  228. package/docs/standards/07-rbac-and-rls-standard.md +430 -7
  229. package/docs/troubleshooting/README.md +2 -2
  230. package/docs/troubleshooting/migration.md +3 -3
  231. package/package.json +1 -3
  232. package/scripts/check-pace-core-compliance.cjs +1 -1
  233. package/scripts/check-pace-core-compliance.js +1 -1
  234. package/src/__tests__/fixtures/supabase.ts +301 -0
  235. package/src/__tests__/public-recipe-view.test.ts +9 -9
  236. package/src/__tests__/rls-policies.test.ts +197 -61
  237. package/src/components/AddressField/AddressField.test.tsx +42 -0
  238. package/src/components/AddressField/AddressField.tsx +71 -60
  239. package/src/components/AddressField/README.md +1 -0
  240. package/src/components/Alert/Alert.test.tsx +50 -10
  241. package/src/components/Alert/Alert.tsx +5 -3
  242. package/src/components/Avatar/Avatar.test.tsx +95 -43
  243. package/src/components/Avatar/Avatar.tsx +16 -16
  244. package/src/components/Button/Button.test.tsx +2 -1
  245. package/src/components/Button/Button.tsx +3 -3
  246. package/src/components/Calendar/Calendar.test.tsx +53 -37
  247. package/src/components/Calendar/Calendar.tsx +409 -82
  248. package/src/components/Card/Card.test.tsx +7 -4
  249. package/src/components/Card/Card.tsx +3 -6
  250. package/src/components/Checkbox/Checkbox.tsx +2 -2
  251. package/src/components/DataTable/components/ActionButtons.tsx +5 -5
  252. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  253. package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
  254. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
  255. package/src/components/DataTable/components/DataTableBody.tsx +12 -12
  256. package/src/components/DataTable/components/DataTableCore.tsx +3 -3
  257. package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
  258. package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
  259. package/src/components/DataTable/components/EditableRow.tsx +2 -2
  260. package/src/components/DataTable/components/EmptyState.tsx +3 -3
  261. package/src/components/DataTable/components/GroupHeader.tsx +2 -2
  262. package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
  263. package/src/components/DataTable/components/ImportModal.tsx +4 -4
  264. package/src/components/DataTable/components/LoadingState.tsx +1 -1
  265. package/src/components/DataTable/components/PaginationControls.tsx +11 -11
  266. package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
  267. package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
  268. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
  269. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
  270. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
  271. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
  272. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
  273. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
  274. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
  275. package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
  276. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
  277. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
  278. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
  279. package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
  280. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
  281. package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
  282. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
  283. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
  284. package/src/components/Dialog/Dialog.tsx +2 -2
  285. package/src/components/EventSelector/EventSelector.tsx +7 -7
  286. package/src/components/FileDisplay/FileDisplay.tsx +291 -179
  287. package/src/components/FileUpload/FileUpload.tsx +7 -4
  288. package/src/components/Header/Header.test.tsx +28 -0
  289. package/src/components/Header/Header.tsx +22 -9
  290. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
  291. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
  292. package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
  293. package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
  294. package/src/components/OrganisationSelector/OrganisationSelector.tsx +8 -8
  295. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
  296. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
  297. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
  298. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
  299. package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
  300. package/src/components/PaceAppLayout/test-setup.tsx +1 -0
  301. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
  302. package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
  303. package/src/components/Progress/Progress.test.tsx +18 -19
  304. package/src/components/Progress/Progress.tsx +31 -32
  305. package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
  306. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
  307. package/src/components/Select/Select.tsx +5 -5
  308. package/src/components/Switch/Switch.test.tsx +2 -1
  309. package/src/components/Switch/Switch.tsx +1 -1
  310. package/src/components/Toast/Toast.tsx +1 -1
  311. package/src/components/Tooltip/Tooltip.test.tsx +8 -2
  312. package/src/components/UserMenu/UserMenu.tsx +3 -3
  313. package/src/eslint-rules/pace-core-compliance.cjs +0 -2
  314. package/src/eslint-rules/pace-core-compliance.js +0 -2
  315. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
  316. package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
  317. package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
  318. package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
  319. package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
  320. package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
  321. package/src/hooks/__tests__/{usePublicEvent.unit.test.ts → usePublicEvent.test.ts} +28 -1
  322. package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
  323. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +58 -16
  324. package/src/hooks/index.ts +1 -1
  325. package/src/hooks/public/usePublicEvent.ts +2 -2
  326. package/src/hooks/public/usePublicFileDisplay.ts +173 -87
  327. package/src/hooks/useAppConfig.ts +24 -5
  328. package/src/hooks/useFileDisplay.ts +297 -34
  329. package/src/hooks/useFileReference.ts +56 -11
  330. package/src/hooks/useFileUrl.ts +1 -1
  331. package/src/hooks/useInactivityTracker.ts +16 -7
  332. package/src/hooks/usePermissionCache.test.ts +85 -8
  333. package/src/hooks/useQueryCache.ts +21 -0
  334. package/src/hooks/useSecureDataAccess.test.ts +80 -35
  335. package/src/hooks/useSecureDataAccess.ts +80 -37
  336. package/src/providers/services/EventServiceProvider.tsx +37 -17
  337. package/src/providers/services/InactivityServiceProvider.tsx +4 -4
  338. package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
  339. package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
  340. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
  341. package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
  342. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
  343. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
  344. package/src/rbac/api.ts +240 -36
  345. package/src/rbac/cache-invalidation.ts +21 -7
  346. package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
  347. package/src/rbac/components/NavigationGuard.tsx +23 -63
  348. package/src/rbac/components/NavigationProvider.test.tsx +52 -23
  349. package/src/rbac/components/NavigationProvider.tsx +13 -11
  350. package/src/rbac/components/PagePermissionGuard.tsx +77 -203
  351. package/src/rbac/components/PagePermissionProvider.tsx +13 -11
  352. package/src/rbac/components/PermissionEnforcer.tsx +24 -62
  353. package/src/rbac/components/RoleBasedRouter.tsx +14 -12
  354. package/src/rbac/components/SecureDataProvider.tsx +13 -11
  355. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
  356. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
  357. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
  358. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
  359. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
  360. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
  361. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
  362. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
  363. package/src/rbac/engine.ts +4 -2
  364. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
  365. package/src/rbac/hooks/index.ts +3 -0
  366. package/src/rbac/hooks/useCan.test.ts +101 -53
  367. package/src/rbac/hooks/usePermissions.ts +108 -41
  368. package/src/rbac/hooks/useRBAC.test.ts +11 -3
  369. package/src/rbac/hooks/useRBAC.ts +83 -40
  370. package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
  371. package/src/rbac/hooks/useResolvedScope.ts +128 -70
  372. package/src/rbac/hooks/useSecureSupabase.ts +36 -19
  373. package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
  374. package/src/rbac/request-deduplication.ts +1 -1
  375. package/src/rbac/secureClient.ts +72 -12
  376. package/src/rbac/security.ts +29 -23
  377. package/src/rbac/types.ts +10 -0
  378. package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
  379. package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
  380. package/src/rbac/utils/__tests__/eventContext.test.ts +6 -1
  381. package/src/rbac/utils/contextValidator.ts +288 -0
  382. package/src/rbac/utils/eventContext.ts +48 -2
  383. package/src/services/EventService.ts +165 -21
  384. package/src/services/OrganisationService.ts +37 -2
  385. package/src/services/__tests__/EventService.test.ts +26 -21
  386. package/src/types/file-reference.ts +13 -10
  387. package/src/utils/app/appNameResolver.test.ts +346 -73
  388. package/src/utils/context/superAdminOverride.ts +58 -0
  389. package/src/utils/file-reference/index.ts +61 -33
  390. package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
  391. package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
  392. package/src/utils/storage/helpers.test.ts +1 -1
  393. package/src/utils/storage/helpers.ts +38 -19
  394. package/src/utils/storage/types.ts +15 -8
  395. package/src/utils/validation/__tests__/csrf.test.ts +105 -0
  396. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
  397. package/src/vite-env.d.ts +2 -2
  398. package/dist/chunk-3GOZZZYH.js.map +0 -1
  399. package/dist/chunk-DDM4CCYT.js.map +0 -1
  400. package/dist/chunk-E7UAOUMY.js +0 -75
  401. package/dist/chunk-E7UAOUMY.js.map +0 -1
  402. package/dist/chunk-F2IMUDXZ.js.map +0 -1
  403. package/dist/chunk-HEHYGYOX.js.map +0 -1
  404. package/dist/chunk-IM4QE42D.js.map +0 -1
  405. package/dist/chunk-MX64ZF6I.js.map +0 -1
  406. package/dist/chunk-SAUPYVLF.js.map +0 -1
  407. package/dist/chunk-THRPYOFK.js.map +0 -1
  408. package/dist/chunk-UCQSRW7Z.js.map +0 -1
  409. package/dist/chunk-VGZZXKBR.js.map +0 -1
  410. package/dist/chunk-YGPFYGA6.js.map +0 -1
  411. package/dist/chunk-YHCN776L.js.map +0 -1
  412. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  413. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  414. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -703
  415. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  416. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
  417. /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-ON3IXISJ.js.map} +0 -0
  418. /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-X5NXANVI.js.map} +0 -0
  419. /package/dist/{api-YP7XD5L6.js.map → api-I6UCQ5S6.js.map} +0 -0
  420. /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
@@ -1,9 +1,6 @@
1
1
  import {
2
2
  useEvents
3
- } from "./chunk-E7UAOUMY.js";
4
- import {
5
- useUnifiedAuth
6
- } from "./chunk-VGZZXKBR.js";
3
+ } from "./chunk-Y4BUBBHD.js";
7
4
  import {
8
5
  assertAppId
9
6
  } from "./chunk-QXHPKYJV.js";
@@ -11,9 +8,8 @@ import {
11
8
  createAddressFromPlaceResult,
12
9
  fetchPlaceAutocomplete,
13
10
  fetchPlaceDetails,
14
- getAddressByPlaceId,
15
- performanceBudgetMonitor
16
- } from "./chunk-YHCN776L.js";
11
+ getAddressByPlaceId
12
+ } from "./chunk-DZWK57KZ.js";
17
13
  import {
18
14
  setOrganisationContext
19
15
  } from "./chunk-VBXEHIUJ.js";
@@ -64,6 +60,20 @@ function runCacheCleanup() {
64
60
  if (typeof window !== "undefined" && !cleanupTimer) {
65
61
  cleanupTimer = setInterval(runCacheCleanup, CLEANUP_INTERVAL_MS);
66
62
  log.debug("Query cache cleanup initialized.");
63
+ window.addEventListener("beforeunload", () => {
64
+ if (cleanupTimer) {
65
+ clearInterval(cleanupTimer);
66
+ cleanupTimer = null;
67
+ log.debug("Query cache cleanup timer cleared on page unload.");
68
+ }
69
+ });
70
+ }
71
+ function cleanupQueryCache() {
72
+ if (cleanupTimer) {
73
+ clearInterval(cleanupTimer);
74
+ cleanupTimer = null;
75
+ log.debug("Query cache cleanup timer cleared.");
76
+ }
67
77
  }
68
78
  function useQueryCache(supabase) {
69
79
  const getCachedQuery = useCallback(async (table, filterKey, filterValue, fetchFn, options = {}) => {
@@ -443,21 +453,22 @@ function validateFileSize(file) {
443
453
  // src/utils/storage/helpers.ts
444
454
  var log2 = createLogger("StorageHelpers");
445
455
  function generateFilePath(options, fileName) {
446
- const { orgId, isPublic = false, customPath } = options;
447
- if (!orgId) {
448
- throw new Error("orgId is required for file path generation");
456
+ const { orgId, userId, isPublic = false, customPath } = options;
457
+ if (!orgId && !userId) {
458
+ throw new Error("Either orgId or userId is required for file path generation");
449
459
  }
460
+ const basePath = orgId ? orgId : `users/${userId}`;
450
461
  if (isPublic) {
451
462
  if (customPath) {
452
- return `${orgId}/${customPath}/${fileName}`;
463
+ return `${basePath}/${customPath}/${fileName}`;
453
464
  }
454
- return `${orgId}/public/${fileName}`;
465
+ return `${basePath}/public/${fileName}`;
455
466
  }
456
467
  if (customPath) {
457
- return `${orgId}/${customPath}/${fileName}`;
468
+ return `${basePath}/${customPath}/${fileName}`;
458
469
  }
459
470
  const pathFolder = customPath || "files";
460
- return `${orgId}/${pathFolder}/${fileName}`;
471
+ return `${basePath}/${pathFolder}/${fileName}`;
461
472
  }
462
473
  function generateUniqueFileName(originalName) {
463
474
  const timestamp = Date.now();
@@ -474,7 +485,8 @@ async function extractFileMetadata(file, options, uploadedBy) {
474
485
  const metadata = {
475
486
  mimeType: file.type,
476
487
  size: file.size,
477
- orgId: options.orgId,
488
+ ...options.orgId && { orgId: options.orgId },
489
+ ...options.userId && { userId: options.userId },
478
490
  appName: options.appName || "pace-core",
479
491
  uploadedBy,
480
492
  uploadedAt: (/* @__PURE__ */ new Date()).toISOString(),
@@ -776,7 +788,11 @@ async function deleteFile(supabase, path, isPublic = false) {
776
788
  async function listFiles(supabase, options) {
777
789
  try {
778
790
  const bucketName = getBucketName(options.isPublic || false);
779
- const pathPrefix = `${options.orgId}/`;
791
+ if (!options.orgId && !options.userId) {
792
+ throw new Error("Either orgId or userId is required for listing files");
793
+ }
794
+ const basePath = options.orgId ? options.orgId : `users/${options.userId}`;
795
+ const pathPrefix = `${basePath}/`;
780
796
  const searchPath = options.pathPrefix ? `${pathPrefix}${options.pathPrefix}` : pathPrefix;
781
797
  const { data, error } = await supabase.storage.from(bucketName).list(searchPath, {
782
798
  limit: options.limit || 100,
@@ -796,7 +812,8 @@ async function listFiles(supabase, options) {
796
812
  metadata: {
797
813
  mimeType: item.metadata?.mimetype || "application/octet-stream",
798
814
  size: item.metadata?.size || 0,
799
- orgId: options.orgId,
815
+ ...options.orgId && { orgId: options.orgId },
816
+ ...options.userId && { userId: options.userId },
800
817
  appName: options.appName,
801
818
  uploadedBy: "unknown",
802
819
  uploadedAt: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
@@ -845,7 +862,14 @@ async function downloadFile(supabase, path, isPublic = false) {
845
862
  async function archiveFile(supabase, path, options) {
846
863
  try {
847
864
  const bucketName = getBucketName(options.isPublic || false);
848
- const archivedPath = path.replace(`${options.orgId}/`, `archived/${options.orgId}/`);
865
+ let archivedPath;
866
+ if (options.orgId) {
867
+ archivedPath = path.replace(`${options.orgId}/`, `archived/${options.orgId}/`);
868
+ } else if (options.userId) {
869
+ archivedPath = path.replace(`users/${options.userId}/`, `archived/users/${options.userId}/`);
870
+ } else {
871
+ throw new Error("Either orgId or userId is required for archiving files");
872
+ }
849
873
  const { error: copyError } = await supabase.storage.from(bucketName).copy(path, archivedPath);
850
874
  if (copyError) {
851
875
  return {
@@ -884,7 +908,7 @@ function usePublicFileDisplay(table_name, record_id, organisation_id, category,
884
908
  const [isLoading, setIsLoading] = useState3(false);
885
909
  const [error, setError] = useState3(null);
886
910
  const fetchFiles = useCallback3(async () => {
887
- if (!table_name || !record_id || !organisation_id || !supabase) {
911
+ if (!table_name || !record_id || !supabase) {
888
912
  setFileUrl(null);
889
913
  setFileReference(null);
890
914
  setFileReferences([]);
@@ -893,11 +917,13 @@ function usePublicFileDisplay(table_name, record_id, organisation_id, category,
893
917
  setIsLoading(false);
894
918
  return;
895
919
  }
896
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
897
- if (!uuidRegex.test(organisation_id)) {
898
- logger.warn("usePublicFileDisplay", "Invalid organisationId format (not a valid UUID)", { organisation_id });
920
+ if (organisation_id) {
921
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
922
+ if (!uuidRegex.test(organisation_id)) {
923
+ logger.warn("usePublicFileDisplay", "Invalid organisationId format (not a valid UUID)", { organisation_id });
924
+ }
899
925
  }
900
- const cacheKey = `public_file_${table_name}_${record_id}_${organisation_id}_${category || "all"}`;
926
+ const cacheKey = `public_file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
901
927
  if (enableCache) {
902
928
  const cached = publicFileCache.get(cacheKey);
903
929
  if (cached && Date.now() - cached.timestamp < cached.ttl) {
@@ -916,77 +942,134 @@ function usePublicFileDisplay(table_name, record_id, organisation_id, category,
916
942
  setIsLoading(true);
917
943
  setError(null);
918
944
  let files = [];
919
- if (category) {
920
- const rpcParams = {
921
- p_table_name: table_name,
922
- p_record_id: record_id,
923
- p_category: category,
924
- p_organisation_id: organisation_id
925
- };
926
- const { data, error: rpcError } = await supabase.rpc("data_file_reference_by_category_list", rpcParams);
927
- if (rpcError) {
928
- logger.error("usePublicFileDisplay", "RPC function error", {
929
- function: "data_file_reference_by_category_list",
930
- table_name,
931
- record_id,
932
- category,
933
- organisation_id,
934
- error: rpcError.message,
935
- errorCode: rpcError.code,
936
- errorDetails: rpcError.details,
937
- errorHint: rpcError.hint
945
+ if (organisation_id === void 0) {
946
+ logger.debug("usePublicFileDisplay", "organisation_id is undefined, searching both user-scoped and organisation-scoped files:", {
947
+ table_name,
948
+ record_id,
949
+ category
950
+ });
951
+ let userScopedFiles = [];
952
+ let orgScopedFiles = [];
953
+ if (category) {
954
+ const { data: userData, error: userRpcError } = await supabase.rpc("data_file_reference_by_category_list", {
955
+ p_table_name: table_name,
956
+ p_record_id: record_id,
957
+ p_category: category,
958
+ p_organisation_id: null
938
959
  });
939
- throw new Error(rpcError.message || "Failed to fetch file reference");
940
- }
941
- if (!data || data.length === 0) {
942
- files = [];
943
- } else {
944
- files = data.filter((item) => {
945
- return item.is_public === true && item.id && item.file_path && item.file_metadata;
946
- }).map((item) => {
947
- return {
960
+ if (!userRpcError && userData) {
961
+ userScopedFiles = userData.filter((item) => item.is_public === true && item.id && item.file_path && item.file_metadata).map((item) => ({
948
962
  id: item.id,
949
963
  table_name,
950
964
  record_id,
951
965
  file_path: item.file_path,
952
966
  file_metadata: item.file_metadata || {},
953
- organisation_id,
967
+ organisation_id: null,
954
968
  app_id: item.file_metadata?.app_id || null,
955
969
  is_public: true,
956
- // RPC already filtered for public files
957
970
  created_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
958
971
  updated_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString()
959
- };
972
+ }));
973
+ }
974
+ } else {
975
+ const { data: userData, error: userRpcError } = await supabase.rpc("data_file_reference_list", {
976
+ p_table_name: table_name,
977
+ p_record_id: record_id,
978
+ p_organisation_id: null
960
979
  });
980
+ if (!userRpcError && userData) {
981
+ const ids = userData.map((item) => item.id);
982
+ if (ids.length > 0) {
983
+ const { data: fullData } = await supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").in("id", ids).eq("is_public", true);
984
+ userScopedFiles = fullData || [];
985
+ }
986
+ }
961
987
  }
962
- } else {
963
- const { data: fileIds, error: rpcError } = await supabase.rpc("data_file_reference_list", {
964
- p_table_name: table_name,
965
- p_record_id: record_id,
966
- p_organisation_id: organisation_id
988
+ const allFiles = [...userScopedFiles, ...orgScopedFiles];
989
+ allFiles.sort((a, b) => {
990
+ const aTime = new Date(a.created_at).getTime();
991
+ const bTime = new Date(b.created_at).getTime();
992
+ return bTime - aTime;
967
993
  });
968
- if (rpcError) {
969
- logger.error("usePublicFileDisplay", "RPC function error", {
970
- function: "data_file_reference_list",
971
- table_name,
972
- record_id,
973
- organisation_id,
974
- error: rpcError.message,
975
- errorCode: rpcError.code,
976
- errorDetails: rpcError.details,
977
- errorHint: rpcError.hint
978
- });
979
- throw new Error(rpcError.message || "Failed to fetch file references");
980
- }
981
- if (!fileIds || fileIds.length === 0) {
982
- files = [];
994
+ files = allFiles;
995
+ logger.debug("usePublicFileDisplay", "Found files with undefined organisation_id:", {
996
+ userScopedCount: userScopedFiles.length,
997
+ orgScopedCount: orgScopedFiles.length,
998
+ totalCount: files.length
999
+ });
1000
+ } else {
1001
+ if (category) {
1002
+ const rpcParams = {
1003
+ p_table_name: table_name,
1004
+ p_record_id: record_id,
1005
+ p_category: category,
1006
+ p_organisation_id: organisation_id ?? null
1007
+ };
1008
+ const { data, error: rpcError } = await supabase.rpc("data_file_reference_by_category_list", rpcParams);
1009
+ if (rpcError) {
1010
+ logger.error("usePublicFileDisplay", "RPC function error", {
1011
+ function: "data_file_reference_by_category_list",
1012
+ table_name,
1013
+ record_id,
1014
+ category,
1015
+ organisation_id,
1016
+ error: rpcError.message,
1017
+ errorCode: rpcError.code,
1018
+ errorDetails: rpcError.details,
1019
+ errorHint: rpcError.hint
1020
+ });
1021
+ throw new Error(rpcError.message || "Failed to fetch file reference");
1022
+ }
1023
+ if (!data || data.length === 0) {
1024
+ files = [];
1025
+ } else {
1026
+ files = data.filter((item) => {
1027
+ return item.is_public === true && item.id && item.file_path && item.file_metadata;
1028
+ }).map((item) => {
1029
+ return {
1030
+ id: item.id,
1031
+ table_name,
1032
+ record_id,
1033
+ file_path: item.file_path,
1034
+ file_metadata: item.file_metadata || {},
1035
+ organisation_id: organisation_id ?? null,
1036
+ app_id: item.file_metadata?.app_id || null,
1037
+ is_public: true,
1038
+ // RPC already filtered for public files
1039
+ created_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString(),
1040
+ updated_at: item.created_at || (/* @__PURE__ */ new Date()).toISOString()
1041
+ };
1042
+ });
1043
+ }
983
1044
  } else {
984
- const ids = fileIds.map((item) => item.id);
985
- const { data: fullData, error: fetchError } = await supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").in("id", ids).eq("is_public", true);
986
- if (fetchError) {
987
- throw new Error(fetchError.message || "Failed to fetch file references");
1045
+ const { data: fileIds, error: rpcError } = await supabase.rpc("data_file_reference_list", {
1046
+ p_table_name: table_name,
1047
+ p_record_id: record_id,
1048
+ p_organisation_id: organisation_id ?? null
1049
+ });
1050
+ if (rpcError) {
1051
+ logger.error("usePublicFileDisplay", "RPC function error", {
1052
+ function: "data_file_reference_list",
1053
+ table_name,
1054
+ record_id,
1055
+ organisation_id,
1056
+ error: rpcError.message,
1057
+ errorCode: rpcError.code,
1058
+ errorDetails: rpcError.details,
1059
+ errorHint: rpcError.hint
1060
+ });
1061
+ throw new Error(rpcError.message || "Failed to fetch file references");
1062
+ }
1063
+ if (!fileIds || fileIds.length === 0) {
1064
+ files = [];
1065
+ } else {
1066
+ const ids = fileIds.map((item) => item.id);
1067
+ const { data: fullData, error: fetchError } = await supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").in("id", ids).eq("is_public", true);
1068
+ if (fetchError) {
1069
+ throw new Error(fetchError.message || "Failed to fetch file references");
1070
+ }
1071
+ files = fullData || [];
988
1072
  }
989
- files = fullData || [];
990
1073
  }
991
1074
  }
992
1075
  const publicFiles = files.filter((f) => f.is_public === true);
@@ -1077,7 +1160,7 @@ function usePublicFileDisplay(table_name, record_id, organisation_id, category,
1077
1160
  }
1078
1161
  }, [table_name, record_id, organisation_id, category, supabase, cacheTtl, enableCache]);
1079
1162
  useEffect4(() => {
1080
- if (table_name && record_id && organisation_id) {
1163
+ if (table_name && record_id) {
1081
1164
  fetchFiles();
1082
1165
  } else {
1083
1166
  setFileUrl(null);
@@ -1090,9 +1173,9 @@ function usePublicFileDisplay(table_name, record_id, organisation_id, category,
1090
1173
  }
1091
1174
  }, [fetchFiles, table_name, record_id, organisation_id]);
1092
1175
  const refetch = useCallback3(async () => {
1093
- if (!table_name || !record_id || !organisation_id) return;
1176
+ if (!table_name || !record_id) return;
1094
1177
  if (enableCache) {
1095
- const cacheKey = `public_file_${table_name}_${record_id}_${organisation_id}_${category || "all"}`;
1178
+ const cacheKey = `public_file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
1096
1179
  publicFileCache.delete(cacheKey);
1097
1180
  }
1098
1181
  await fetchFiles();
@@ -1148,8 +1231,9 @@ var FileReferenceServiceImpl = class {
1148
1231
  */
1149
1232
  async createFileReference(options, file) {
1150
1233
  try {
1151
- if (!options.organisation_id) {
1152
- throw new Error("organisation_id is required for file upload");
1234
+ const isUserScoped = !options.organisation_id && options.userId;
1235
+ if (!isUserScoped && !options.organisation_id) {
1236
+ throw new Error("organisation_id is required for file upload, or userId must be provided for user-scoped files");
1153
1237
  }
1154
1238
  if (!options.table_name) {
1155
1239
  throw new Error("table_name is required for file upload");
@@ -1160,9 +1244,20 @@ var FileReferenceServiceImpl = class {
1160
1244
  if (!options.folder) {
1161
1245
  throw new Error("folder is required for file upload. The folder prop determines the storage path.");
1162
1246
  }
1247
+ let authenticatedUserId = void 0;
1248
+ if (isUserScoped) {
1249
+ const { data: { user: authUser }, error: authError } = await this.supabase.auth.getUser();
1250
+ if (authError || !authUser) {
1251
+ throw new Error("User must be authenticated to upload user-scoped files");
1252
+ }
1253
+ authenticatedUserId = authUser.id;
1254
+ log3.debug("Using authenticated user ID for user-scoped file upload", { userId: authenticatedUserId });
1255
+ }
1163
1256
  const uploadResult = await uploadFile(this.supabase, file, {
1164
1257
  appName: "file-reference",
1165
- orgId: options.organisation_id,
1258
+ orgId: options.organisation_id || void 0,
1259
+ userId: authenticatedUserId || (isUserScoped ? void 0 : options.userId),
1260
+ // Use auth.uid() for user-scoped files
1166
1261
  isPublic: options.is_public || false,
1167
1262
  customPath: options.folder
1168
1263
  // Use folder prop as the custom path segment
@@ -1176,16 +1271,20 @@ var FileReferenceServiceImpl = class {
1176
1271
  const filePath = uploadResult.path;
1177
1272
  const metadata = await extractFileMetadata(file, {
1178
1273
  appName: "file-reference",
1179
- orgId: options.organisation_id,
1274
+ orgId: options.organisation_id || void 0,
1275
+ userId: authenticatedUserId || (isUserScoped ? void 0 : options.userId),
1276
+ // Use auth.uid() for user-scoped files
1180
1277
  isPublic: options.is_public || false
1181
1278
  }, "system");
1182
- await setOrganisationContext(this.supabase, options.organisation_id);
1279
+ if (!isUserScoped && options.organisation_id) {
1280
+ await setOrganisationContext(this.supabase, options.organisation_id);
1281
+ }
1183
1282
  const { data, error } = await this.supabase.rpc("data_file_reference_create", {
1184
1283
  p_table_name: options.table_name,
1185
1284
  p_record_id: options.record_id,
1186
1285
  p_file_path: filePath,
1187
1286
  // Storage path from step 1
1188
- p_organisation_id: options.organisation_id,
1287
+ p_organisation_id: options.organisation_id ?? null,
1189
1288
  p_app_id: options.app_id,
1190
1289
  p_page_context: options.pageContext,
1191
1290
  p_event_id: options.event_id || null,
@@ -1198,7 +1297,9 @@ var FileReferenceServiceImpl = class {
1198
1297
  ...metadata,
1199
1298
  ...options.custom_metadata
1200
1299
  },
1201
- p_is_public: options.is_public || false
1300
+ p_is_public: options.is_public || false,
1301
+ p_user_id: authenticatedUserId || options.userId || null
1302
+ // Pass authenticated user ID for user-scoped files
1202
1303
  });
1203
1304
  if (error) {
1204
1305
  await deleteFile(this.supabase, filePath, options.is_public || false);
@@ -1216,7 +1317,7 @@ var FileReferenceServiceImpl = class {
1216
1317
  invalidateFileDisplayCache(
1217
1318
  options.table_name,
1218
1319
  options.record_id,
1219
- options.organisation_id,
1320
+ options.organisation_id || null,
1220
1321
  options.category
1221
1322
  );
1222
1323
  return fileRef;
@@ -1227,7 +1328,13 @@ var FileReferenceServiceImpl = class {
1227
1328
  }
1228
1329
  async getFileReference(table_name, record_id, organisation_id) {
1229
1330
  try {
1230
- const { data, error } = await this.supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").eq("table_name", table_name).eq("record_id", record_id).eq("organisation_id", organisation_id).single();
1331
+ let query = this.supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").eq("table_name", table_name).eq("record_id", record_id);
1332
+ if (organisation_id === null || organisation_id === void 0) {
1333
+ query = query.is("organisation_id", null);
1334
+ } else {
1335
+ query = query.eq("organisation_id", organisation_id);
1336
+ }
1337
+ const { data, error } = await query.single();
1231
1338
  if (error) {
1232
1339
  if (error.code === "PGRST116") {
1233
1340
  return null;
@@ -1269,7 +1376,7 @@ var FileReferenceServiceImpl = class {
1269
1376
  const { data: filePath, error } = await this.supabase.rpc("data_file_reference_signed_url_get", {
1270
1377
  p_table_name: table_name,
1271
1378
  p_record_id: record_id,
1272
- p_organisation_id: organisation_id,
1379
+ p_organisation_id: organisation_id ?? null,
1273
1380
  p_expires_in: expires_in
1274
1381
  });
1275
1382
  if (error) {
@@ -1281,6 +1388,7 @@ var FileReferenceServiceImpl = class {
1281
1388
  const signedUrlResult = await getSignedUrl(this.supabase, filePath, {
1282
1389
  appName: "file-reference",
1283
1390
  orgId: organisation_id,
1391
+ userId: organisation_id ? void 0 : record_id,
1284
1392
  expiresIn: expires_in
1285
1393
  });
1286
1394
  return signedUrlResult?.url || null;
@@ -1307,7 +1415,7 @@ var FileReferenceServiceImpl = class {
1307
1415
  const { error } = await this.supabase.rpc("data_file_reference_delete", {
1308
1416
  p_table_name: table_name,
1309
1417
  p_record_id: record_id,
1310
- p_organisation_id: organisation_id,
1418
+ p_organisation_id: organisation_id ?? null,
1311
1419
  p_delete_file: delete_file
1312
1420
  });
1313
1421
  if (error) {
@@ -1327,7 +1435,7 @@ var FileReferenceServiceImpl = class {
1327
1435
  const { data, error } = await this.supabase.rpc("data_file_reference_list", {
1328
1436
  p_table_name: table_name,
1329
1437
  p_record_id: record_id,
1330
- p_organisation_id: organisation_id
1438
+ p_organisation_id: organisation_id ?? null
1331
1439
  });
1332
1440
  if (error) {
1333
1441
  throw new Error(`Failed to list file references: ${error.message}`);
@@ -1348,7 +1456,7 @@ var FileReferenceServiceImpl = class {
1348
1456
  fileType,
1349
1457
  ...item.file_metadata || {}
1350
1458
  },
1351
- organisation_id,
1459
+ organisation_id: organisation_id ?? null,
1352
1460
  app_id: item.file_metadata?.app_id ? assertAppId(item.file_metadata.app_id) : assertAppId(""),
1353
1461
  // May not be in metadata, use empty string
1354
1462
  is_public: item.is_public ?? false,
@@ -1369,7 +1477,7 @@ var FileReferenceServiceImpl = class {
1369
1477
  const { data, error } = await this.supabase.rpc("data_file_reference_count_get", {
1370
1478
  p_table_name: table_name,
1371
1479
  p_record_id: record_id,
1372
- p_organisation_id: organisation_id
1480
+ p_organisation_id: organisation_id ?? null
1373
1481
  });
1374
1482
  if (error) {
1375
1483
  throw new Error(`Failed to get file count: ${error.message}`);
@@ -1384,7 +1492,7 @@ var FileReferenceServiceImpl = class {
1384
1492
  try {
1385
1493
  const { data, error } = await this.supabase.rpc("data_file_reference_get", {
1386
1494
  p_file_reference_id: id,
1387
- p_organisation_id: organisation_id
1495
+ p_organisation_id: organisation_id ?? null
1388
1496
  });
1389
1497
  if (error) {
1390
1498
  throw new Error(`Failed to get file reference by ID: ${error.message}`);
@@ -1404,7 +1512,7 @@ var FileReferenceServiceImpl = class {
1404
1512
  p_table_name: table_name,
1405
1513
  p_record_id: record_id,
1406
1514
  p_category: category,
1407
- p_organisation_id: organisation_id
1515
+ p_organisation_id: organisation_id ?? null
1408
1516
  });
1409
1517
  if (error) {
1410
1518
  log3.error("RPC ERROR getting files by category:", {
@@ -1448,7 +1556,7 @@ var FileReferenceServiceImpl = class {
1448
1556
  category: item.file_metadata?.category || "general_documents" /* GENERAL_DOCUMENTS */,
1449
1557
  ...item.file_metadata || {}
1450
1558
  },
1451
- organisation_id,
1559
+ organisation_id: organisation_id ?? null,
1452
1560
  app_id: item.file_metadata?.app_id ? assertAppId(item.file_metadata.app_id) : assertAppId(""),
1453
1561
  // May not be in metadata, use empty string
1454
1562
  is_public: item.is_public ?? false,
@@ -1502,7 +1610,8 @@ async function uploadFileWithReference(supabase, options, file) {
1502
1610
  const fileReference = await service.createFileReference(options, file);
1503
1611
  const fileUrl = options.is_public ? getPublicUrl(supabase, fileReference.file_path, true) : await getSignedUrl(supabase, fileReference.file_path, {
1504
1612
  appName: "file-reference",
1505
- orgId: options.organisation_id,
1613
+ orgId: options.organisation_id || void 0,
1614
+ userId: options.userId || void 0,
1506
1615
  expiresIn: 3600
1507
1616
  });
1508
1617
  const urlString = typeof fileUrl === "string" ? fileUrl : fileUrl?.url || "";
@@ -1547,7 +1656,7 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1547
1656
  const [isLoading, setIsLoading] = useState4(false);
1548
1657
  const [error, setError] = useState4(null);
1549
1658
  const fetchFiles = useCallback4(async () => {
1550
- if (!table_name || !record_id || !organisation_id || !supabase) {
1659
+ if (!table_name || !record_id || !supabase) {
1551
1660
  setFileUrl(null);
1552
1661
  setFileReference(null);
1553
1662
  setFileReferences([]);
@@ -1556,11 +1665,13 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1556
1665
  setIsLoading(false);
1557
1666
  return;
1558
1667
  }
1559
- const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1560
- if (!uuidRegex.test(organisation_id)) {
1561
- logger.warn("useFileDisplay", "Invalid organisationId format (not a valid UUID):", organisation_id);
1668
+ if (organisation_id) {
1669
+ const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
1670
+ if (!uuidRegex.test(organisation_id)) {
1671
+ logger.warn("useFileDisplay", "Invalid organisationId format (not a valid UUID):", organisation_id);
1672
+ }
1562
1673
  }
1563
- const cacheKey = `file_${table_name}_${record_id}_${organisation_id}_${category || "all"}`;
1674
+ const cacheKey = `file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
1564
1675
  if (enableCache) {
1565
1676
  const cached = authenticatedFileCache.get(cacheKey);
1566
1677
  if (cached && Date.now() - cached.timestamp < cached.ttl) {
@@ -1570,6 +1681,7 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1570
1681
  const signedUrlResult = await getSignedUrl(supabase, cachedData.fileReference.file_path, {
1571
1682
  appName: "pace-core",
1572
1683
  orgId: organisation_id,
1684
+ userId: organisation_id ? void 0 : record_id,
1573
1685
  expiresIn: 3600
1574
1686
  });
1575
1687
  const regeneratedUrl = signedUrlResult?.url || null;
@@ -1600,25 +1712,205 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1600
1712
  setError(null);
1601
1713
  const service = createFileReferenceService(supabase);
1602
1714
  let files = [];
1603
- if (category) {
1604
- logger.debug("useFileDisplay", "Using RPC function for category filtering:", {
1605
- table_name,
1606
- record_id,
1607
- category,
1608
- organisation_id
1715
+ const shouldSearchBothScopes = organisation_id === void 0;
1716
+ if (shouldSearchBothScopes) {
1717
+ let userScopedFiles = [];
1718
+ let orgScopedFiles = [];
1719
+ try {
1720
+ if (category) {
1721
+ userScopedFiles = await service.getFilesByCategory(
1722
+ table_name,
1723
+ record_id,
1724
+ category,
1725
+ void 0
1726
+ // Explicitly pass undefined for user-scoped files (service converts to null for RPC)
1727
+ );
1728
+ } else {
1729
+ userScopedFiles = await service.listFileReferences(
1730
+ table_name,
1731
+ record_id,
1732
+ void 0
1733
+ // Explicitly pass undefined for user-scoped files (service converts to null for RPC)
1734
+ );
1735
+ }
1736
+ } catch (err) {
1737
+ logger.warn("useFileDisplay", "Error querying user-scoped files:", err);
1738
+ userScopedFiles = [];
1739
+ }
1740
+ try {
1741
+ const { data: { user }, error: userError } = await supabase.auth.getUser();
1742
+ if (userError) {
1743
+ logger.warn("useFileDisplay", "Error getting user:", userError);
1744
+ }
1745
+ if (user) {
1746
+ const { data: memberships, error: membershipError } = await supabase.from("organisation_memberships").select("organisation_id").eq("user_id", user.id).or("status.is.null,status.eq.active");
1747
+ if (membershipError) {
1748
+ logger.warn("useFileDisplay", "Error querying organisation memberships:", membershipError);
1749
+ }
1750
+ if (memberships && memberships.length > 0) {
1751
+ const orgIds = memberships.map((m) => m.organisation_id).filter(Boolean);
1752
+ const orgQueries = orgIds.map(async (orgId) => {
1753
+ try {
1754
+ if (category) {
1755
+ return await service.getFilesByCategory(
1756
+ table_name,
1757
+ record_id,
1758
+ category,
1759
+ orgId
1760
+ );
1761
+ } else {
1762
+ return await service.listFileReferences(
1763
+ table_name,
1764
+ record_id,
1765
+ orgId
1766
+ );
1767
+ }
1768
+ } catch (err) {
1769
+ return [];
1770
+ }
1771
+ });
1772
+ const orgResults = await Promise.all(orgQueries);
1773
+ orgScopedFiles = orgResults.flat();
1774
+ } else {
1775
+ try {
1776
+ let fallbackQuery = supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").eq("table_name", table_name).eq("record_id", record_id).order("created_at", { ascending: false });
1777
+ if (category) {
1778
+ fallbackQuery = fallbackQuery.eq("file_metadata->>category", category);
1779
+ }
1780
+ const { data: fallbackFiles } = await fallbackQuery;
1781
+ if (fallbackFiles && fallbackFiles.length > 0) {
1782
+ orgScopedFiles = fallbackFiles.map((f) => ({
1783
+ id: f.id,
1784
+ table_name: f.table_name,
1785
+ record_id: f.record_id,
1786
+ file_path: f.file_path,
1787
+ file_metadata: f.file_metadata || {},
1788
+ organisation_id: f.organisation_id,
1789
+ app_id: f.app_id,
1790
+ is_public: f.is_public ?? false,
1791
+ created_at: f.created_at,
1792
+ updated_at: f.updated_at
1793
+ }));
1794
+ }
1795
+ } catch (err) {
1796
+ }
1797
+ }
1798
+ }
1799
+ } catch (err) {
1800
+ logger.warn("useFileDisplay", "Error querying organisation-scoped files:", err);
1801
+ orgScopedFiles = [];
1802
+ }
1803
+ const allFiles = [...userScopedFiles, ...orgScopedFiles];
1804
+ allFiles.sort((a, b) => {
1805
+ const aTime = new Date(a.created_at).getTime();
1806
+ const bTime = new Date(b.created_at).getTime();
1807
+ return bTime - aTime;
1609
1808
  });
1610
- files = await service.getFilesByCategory(
1611
- table_name,
1612
- record_id,
1613
- category,
1614
- organisation_id
1615
- );
1809
+ if (orgScopedFiles.length > 0 && userScopedFiles.length > 0) {
1810
+ files = allFiles.filter((f) => f.organisation_id !== null);
1811
+ } else {
1812
+ files = allFiles;
1813
+ }
1814
+ if (files.length === 0) {
1815
+ try {
1816
+ let directQuery = supabase.from("file_references").select("id, table_name, record_id, file_path, file_metadata, organisation_id, app_id, is_public, created_at, updated_at").eq("table_name", table_name).eq("record_id", record_id).order("created_at", { ascending: false });
1817
+ if (category) {
1818
+ directQuery = directQuery.eq("file_metadata->>category", category);
1819
+ }
1820
+ const { data: directFiles } = await directQuery;
1821
+ if (directFiles && directFiles.length > 0) {
1822
+ files = directFiles.map((f) => ({
1823
+ id: f.id,
1824
+ table_name: f.table_name,
1825
+ record_id: f.record_id,
1826
+ file_path: f.file_path,
1827
+ file_metadata: f.file_metadata || {},
1828
+ organisation_id: f.organisation_id,
1829
+ app_id: f.app_id,
1830
+ is_public: f.is_public ?? false,
1831
+ created_at: f.created_at,
1832
+ updated_at: f.updated_at
1833
+ }));
1834
+ }
1835
+ } catch (err) {
1836
+ }
1837
+ }
1616
1838
  } else {
1617
- files = await service.listFileReferences(
1618
- table_name,
1619
- record_id,
1620
- organisation_id
1621
- );
1839
+ if (category) {
1840
+ logger.debug("useFileDisplay", "Using RPC function for category filtering:", {
1841
+ table_name,
1842
+ record_id,
1843
+ category,
1844
+ organisation_id
1845
+ });
1846
+ files = await service.getFilesByCategory(
1847
+ table_name,
1848
+ record_id,
1849
+ category,
1850
+ organisation_id
1851
+ );
1852
+ } else {
1853
+ files = await service.listFileReferences(
1854
+ table_name,
1855
+ record_id,
1856
+ organisation_id
1857
+ );
1858
+ }
1859
+ if (files.length === 0 && (!organisation_id || organisation_id === "")) {
1860
+ let userScopedFiles = [];
1861
+ let orgScopedFiles = [];
1862
+ try {
1863
+ if (category) {
1864
+ userScopedFiles = await service.getFilesByCategory(
1865
+ table_name,
1866
+ record_id,
1867
+ category,
1868
+ void 0
1869
+ );
1870
+ } else {
1871
+ userScopedFiles = await service.listFileReferences(
1872
+ table_name,
1873
+ record_id,
1874
+ void 0
1875
+ );
1876
+ }
1877
+ } catch (err) {
1878
+ }
1879
+ try {
1880
+ const { data: { user } } = await supabase.auth.getUser();
1881
+ if (user) {
1882
+ const { data: memberships } = await supabase.from("organisation_memberships").select("organisation_id").eq("user_id", user.id).or("status.is.null,status.eq.active");
1883
+ if (memberships && memberships.length > 0) {
1884
+ const orgIds = memberships.map((m) => m.organisation_id).filter(Boolean);
1885
+ const orgQueries = orgIds.map(async (orgId) => {
1886
+ try {
1887
+ if (category) {
1888
+ return await service.getFilesByCategory(table_name, record_id, category, orgId);
1889
+ } else {
1890
+ return await service.listFileReferences(table_name, record_id, orgId);
1891
+ }
1892
+ } catch (err) {
1893
+ return [];
1894
+ }
1895
+ });
1896
+ const orgResults = await Promise.all(orgQueries);
1897
+ orgScopedFiles = orgResults.flat();
1898
+ }
1899
+ }
1900
+ } catch (err) {
1901
+ }
1902
+ const allFiles = [...userScopedFiles, ...orgScopedFiles];
1903
+ allFiles.sort((a, b) => {
1904
+ const aTime = new Date(a.created_at).getTime();
1905
+ const bTime = new Date(b.created_at).getTime();
1906
+ return bTime - aTime;
1907
+ });
1908
+ if (orgScopedFiles.length > 0 && userScopedFiles.length > 0) {
1909
+ files = allFiles.filter((f) => f.organisation_id !== null);
1910
+ } else {
1911
+ files = allFiles;
1912
+ }
1913
+ }
1622
1914
  }
1623
1915
  if (files.length === 0) {
1624
1916
  setFileUrl(null);
@@ -1656,6 +1948,7 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1656
1948
  const signedUrlResult = await getSignedUrl(supabase, firstFile.file_path, {
1657
1949
  appName: "pace-core",
1658
1950
  orgId: organisation_id,
1951
+ userId: organisation_id ? void 0 : record_id,
1659
1952
  expiresIn: 3600
1660
1953
  });
1661
1954
  url = signedUrlResult?.url || null;
@@ -1667,6 +1960,7 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1667
1960
  const urlMap = await generateFileUrlsBatch(supabase, files, {
1668
1961
  appName: "pace-core",
1669
1962
  orgId: organisation_id,
1963
+ userId: organisation_id ? void 0 : record_id,
1670
1964
  expiresIn: 3600
1671
1965
  });
1672
1966
  setFileUrls(urlMap);
@@ -1720,7 +2014,7 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1720
2014
  }
1721
2015
  }, [table_name, record_id, organisation_id, category, supabase, cacheTtl, enableCache]);
1722
2016
  useEffect5(() => {
1723
- if (table_name && record_id && organisation_id && supabase) {
2017
+ if (table_name && record_id && supabase) {
1724
2018
  fetchFiles();
1725
2019
  } else {
1726
2020
  setFileUrl(null);
@@ -1731,11 +2025,11 @@ function useFileDisplay(table_name, record_id, organisation_id, category, option
1731
2025
  setIsLoading(false);
1732
2026
  setError(null);
1733
2027
  }
1734
- }, [fetchFiles, table_name, record_id, organisation_id, supabase]);
2028
+ }, [table_name, record_id, organisation_id, supabase]);
1735
2029
  const refetch = useCallback4(async () => {
1736
- if (!table_name || !record_id || !organisation_id || !supabase) return;
2030
+ if (!table_name || !record_id || !supabase) return;
1737
2031
  if (enableCache) {
1738
- const cacheKey = `file_${table_name}_${record_id}_${organisation_id}_${category || "all"}`;
2032
+ const cacheKey = `file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
1739
2033
  authenticatedFileCache.delete(cacheKey);
1740
2034
  }
1741
2035
  await fetchFiles();
@@ -1766,210 +2060,14 @@ function getFileDisplayCacheStats() {
1766
2060
  };
1767
2061
  }
1768
2062
  function invalidateFileDisplayCache(table_name, record_id, organisation_id, category) {
1769
- const cacheKey = `file_${table_name}_${record_id}_${organisation_id}_${category || "all"}`;
2063
+ const cacheKey = `file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_${category || "all"}`;
1770
2064
  authenticatedFileCache.delete(cacheKey);
1771
2065
  if (category) {
1772
- const allCategoryKey = `file_${table_name}_${record_id}_${organisation_id}_all`;
2066
+ const allCategoryKey = `file_${table_name}_${record_id}_${organisation_id === void 0 ? "undefined" : organisation_id ?? "null"}_all`;
1773
2067
  authenticatedFileCache.delete(allCategoryKey);
1774
2068
  }
1775
2069
  }
1776
2070
 
1777
- // src/components/ErrorBoundary/ErrorBoundary.tsx
1778
- import { Component } from "react";
1779
- import { jsx, jsxs } from "react/jsx-runtime";
1780
- var ErrorBoundary = class extends Component {
1781
- constructor(props) {
1782
- super(props);
1783
- this.retryTimeoutId = null;
1784
- this.reportError = (errorId, componentName) => {
1785
- if (import.meta.env.MODE === "production") {
1786
- logger.warn("ErrorBoundary", "Error reporting would be triggered in production:", { errorId, componentName });
1787
- }
1788
- };
1789
- this.handleRetry = () => {
1790
- const { maxRetries = 3 } = this.props;
1791
- const { retryCount } = this.state;
1792
- if (retryCount < maxRetries) {
1793
- logger.debug("ErrorBoundary", `Retrying component render (attempt ${retryCount + 1}/${maxRetries})`);
1794
- this.setState((prevState) => ({
1795
- hasError: false,
1796
- error: void 0,
1797
- errorInfo: void 0,
1798
- errorId: void 0,
1799
- retryCount: prevState.retryCount + 1
1800
- }));
1801
- }
1802
- };
1803
- this.state = {
1804
- hasError: false,
1805
- retryCount: 0
1806
- };
1807
- }
1808
- static getDerivedStateFromError(error) {
1809
- const errorId = `error_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
1810
- return {
1811
- hasError: true,
1812
- error,
1813
- errorId
1814
- };
1815
- }
1816
- componentDidCatch(error, errorInfo) {
1817
- const { componentName = "Unknown Component", onError, enableReporting = true } = this.props;
1818
- const errorId = this.state.errorId;
1819
- this.setState({ errorInfo });
1820
- logger.error("ErrorBoundary", `[${componentName}] Caught error ${errorId}:`, error, errorInfo);
1821
- performanceBudgetMonitor.measure("ERROR_BOUNDARY_TRIGGER", 1, {
1822
- componentName,
1823
- errorId,
1824
- errorMessage: error.message,
1825
- stack: error.stack?.substring(0, 200)
1826
- // Truncated stack trace
1827
- });
1828
- if (enableReporting) {
1829
- this.reportError(errorId, componentName);
1830
- }
1831
- if (onError) {
1832
- onError(error, errorInfo, errorId);
1833
- }
1834
- }
1835
- componentWillUnmount() {
1836
- if (this.retryTimeoutId) {
1837
- clearTimeout(this.retryTimeoutId);
1838
- }
1839
- }
1840
- render() {
1841
- if (this.state.hasError) {
1842
- const {
1843
- componentName = "Component",
1844
- fallback,
1845
- enableRetry = true,
1846
- maxRetries = 3
1847
- } = this.props;
1848
- const { retryCount, errorId } = this.state;
1849
- if (fallback) {
1850
- return fallback;
1851
- }
1852
- return /* @__PURE__ */ jsx(
1853
- "div",
1854
- {
1855
- role: "alert",
1856
- className: "p-6 bg-destructive/10 border border-destructive/20 rounded-lg",
1857
- "data-error-boundary": errorId,
1858
- children: /* @__PURE__ */ jsxs("div", { className: "flex items-start gap-3", children: [
1859
- /* @__PURE__ */ jsx("div", { className: "flex-shrink-0", children: /* @__PURE__ */ jsx("svg", { className: "w-5 h-5 text-destructive", viewBox: "0 0 20 20", fill: "currentColor", children: /* @__PURE__ */ jsx("path", { fillRule: "evenodd", d: "M18 10a8 8 0 11-16 0 8 8 0 0116 0zm-7 4a1 1 0 11-2 0 1 1 0 012 0zm-1-9a1 1 0 00-1 1v4a1 1 0 102 0V6a1 1 0 00-1-1z", clipRule: "evenodd" }) }) }),
1860
- /* @__PURE__ */ jsxs("div", { className: "flex-1 min-w-0", children: [
1861
- /* @__PURE__ */ jsxs("h3", { className: "text-destructive", children: [
1862
- "Error in ",
1863
- componentName
1864
- ] }),
1865
- /* @__PURE__ */ jsx("p", { className: "text-destructive/80", children: this.state.error?.message || "An unexpected error occurred." }),
1866
- enableRetry && retryCount < maxRetries && /* @__PURE__ */ jsxs("div", { className: "flex gap-3 mb-4", children: [
1867
- /* @__PURE__ */ jsxs(
1868
- "button",
1869
- {
1870
- onClick: this.handleRetry,
1871
- className: "px-4 py-2 bg-destructive text-destructive-foreground rounded-md hover:bg-destructive/90 transition-colors text-sm font-medium",
1872
- children: [
1873
- "Retry (",
1874
- retryCount + 1,
1875
- "/",
1876
- maxRetries,
1877
- ")"
1878
- ]
1879
- }
1880
- ),
1881
- /* @__PURE__ */ jsx(
1882
- "button",
1883
- {
1884
- onClick: () => window.location.reload(),
1885
- className: "px-4 py-2 bg-sec-600 text-main-50 rounded-md hover:bg-sec-700 transition-colors text-sm font-medium",
1886
- children: "Reload Page"
1887
- }
1888
- )
1889
- ] }),
1890
- retryCount >= maxRetries && /* @__PURE__ */ jsxs("div", { className: "mb-4 p-3 bg-acc-50 border border-acc-200 rounded-md", children: [
1891
- /* @__PURE__ */ jsx("p", { className: "text-acc-800", children: "Maximum retry attempts reached. Please reload the page or contact support." }),
1892
- /* @__PURE__ */ jsx(
1893
- "button",
1894
- {
1895
- onClick: () => window.location.reload(),
1896
- className: "mt-2 px-3 py-1 bg-acc-600 text-main-50 rounded text-sm hover:bg-acc-700",
1897
- children: "Reload Page"
1898
- }
1899
- )
1900
- ] }),
1901
- import.meta.env.MODE === "development" && this.state.error && /* @__PURE__ */ jsxs("details", { className: "text-sm text-destructive/70", children: [
1902
- /* @__PURE__ */ jsx("summary", { className: "cursor-pointer font-medium mb-2", children: "Error Details (Development)" }),
1903
- /* @__PURE__ */ jsxs("div", { className: "bg-destructive/5 p-3 rounded border", children: [
1904
- /* @__PURE__ */ jsxs("p", { className: "font-mono", children: [
1905
- "Error ID: ",
1906
- errorId
1907
- ] }),
1908
- /* @__PURE__ */ jsxs("pre", { className: "whitespace-pre-wrap text-xs overflow-auto max-h-32", children: [
1909
- this.state.error.toString(),
1910
- this.state.errorInfo?.componentStack
1911
- ] })
1912
- ] })
1913
- ] })
1914
- ] })
1915
- ] })
1916
- }
1917
- );
1918
- }
1919
- return this.props.children;
1920
- }
1921
- };
1922
-
1923
- // src/components/PublicLayout/PublicPageProvider.tsx
1924
- import { createContext, useContext, useMemo as useMemo2 } from "react";
1925
- import { createClient } from "@supabase/supabase-js";
1926
- import { jsx as jsx2 } from "react/jsx-runtime";
1927
- var PublicPageContext = createContext(void 0);
1928
- function PublicPageProvider({ children, appName }) {
1929
- const getEnvVar = (key) => {
1930
- if (typeof import.meta !== "undefined" && import.meta.env) {
1931
- const env = import.meta.env;
1932
- return env[key];
1933
- }
1934
- if (typeof process !== "undefined" && process.env) {
1935
- return process.env[key];
1936
- }
1937
- return void 0;
1938
- };
1939
- const supabaseUrl = getEnvVar("VITE_SUPABASE_URL") || getEnvVar("NEXT_PUBLIC_SUPABASE_URL") || null;
1940
- const supabaseKey = getEnvVar("VITE_SUPABASE_ANON_KEY") || getEnvVar("NEXT_PUBLIC_SUPABASE_ANON_KEY") || null;
1941
- const supabase = useMemo2(() => {
1942
- if (!supabaseUrl || !supabaseKey) {
1943
- logger.warn("PublicPageProvider", "Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment. Use publishable key if anon key is disabled.");
1944
- return null;
1945
- }
1946
- const client = createClient(supabaseUrl, supabaseKey);
1947
- logger.info("PublicPageProvider", "Supabase client created successfully for public pages");
1948
- return client;
1949
- }, [supabaseUrl, supabaseKey]);
1950
- const contextValue = {
1951
- isPublicPage: true,
1952
- supabase,
1953
- appName: appName || null,
1954
- environment: {
1955
- supabaseUrl,
1956
- supabaseKey
1957
- }
1958
- };
1959
- return /* @__PURE__ */ jsx2(PublicPageContext.Provider, { value: contextValue, children: /* @__PURE__ */ jsx2(ErrorBoundary, { componentName: "PublicPageProvider", children }) });
1960
- }
1961
- function usePublicPageContext() {
1962
- const context = useContext(PublicPageContext);
1963
- if (!context) {
1964
- throw new Error("usePublicPageContext must be used within a PublicPageProvider");
1965
- }
1966
- return context;
1967
- }
1968
- function useIsPublicPage() {
1969
- const context = useContext(PublicPageContext);
1970
- return context !== void 0;
1971
- }
1972
-
1973
2071
  // src/hooks/useEventTheme.ts
1974
2072
  import { useEffect as useEffect6 } from "react";
1975
2073
  import { useLocation } from "react-router-dom";
@@ -2059,54 +2157,9 @@ function usePreventTabReload(options = {}) {
2059
2157
  }, [enabled, gracePeriodMs]);
2060
2158
  }
2061
2159
 
2062
- // src/hooks/useAppConfig.ts
2063
- import { useMemo as useMemo3, useContext as useContext2 } from "react";
2064
- function useAppConfig() {
2065
- const isPublicPage = useIsPublicPage();
2066
- const publicPageContext = useContext2(PublicPageContext);
2067
- const contextAppName = publicPageContext?.appName || null;
2068
- if (isPublicPage) {
2069
- const getAppName = () => {
2070
- if (contextAppName) {
2071
- return contextAppName;
2072
- }
2073
- if (typeof import.meta !== "undefined" && import.meta.env) {
2074
- return import.meta.env.VITE_APP_NAME || import.meta.env.NEXT_PUBLIC_APP_NAME || "PACE";
2075
- }
2076
- if (typeof import.meta !== "undefined" && import.meta.env) {
2077
- return import.meta.env.VITE_APP_NAME || import.meta.env.NEXT_PUBLIC_APP_NAME || "PACE";
2078
- }
2079
- return "PACE";
2080
- };
2081
- return useMemo3(() => ({
2082
- supportsDirectAccess: false,
2083
- // Public pages don't support direct access
2084
- requiresEvent: true,
2085
- // Public pages always require an event
2086
- isLoading: false,
2087
- appName: getAppName()
2088
- }), [contextAppName]);
2089
- }
2090
- try {
2091
- const { appConfig, appName } = useUnifiedAuth();
2092
- return useMemo3(() => ({
2093
- supportsDirectAccess: !(appConfig?.requires_event ?? true),
2094
- requiresEvent: appConfig?.requires_event ?? true,
2095
- isLoading: appConfig === null,
2096
- appName
2097
- }), [appConfig?.requires_event, appName]);
2098
- } catch (error) {
2099
- return useMemo3(() => ({
2100
- supportsDirectAccess: false,
2101
- requiresEvent: true,
2102
- isLoading: false,
2103
- appName: "PACE"
2104
- }), []);
2105
- }
2106
- }
2107
-
2108
2160
  export {
2109
2161
  useDebounce,
2162
+ cleanupQueryCache,
2110
2163
  useQueryCache,
2111
2164
  queryCacheHelpers,
2112
2165
  useAddressAutocomplete,
@@ -2137,13 +2190,7 @@ export {
2137
2190
  clearFileDisplayCache,
2138
2191
  getFileDisplayCacheStats,
2139
2192
  invalidateFileDisplayCache,
2140
- ErrorBoundary,
2141
- PublicPageContext,
2142
- PublicPageProvider,
2143
- usePublicPageContext,
2144
- useIsPublicPage,
2145
2193
  useEventTheme,
2146
- usePreventTabReload,
2147
- useAppConfig
2194
+ usePreventTabReload
2148
2195
  };
2149
- //# sourceMappingURL=chunk-UCQSRW7Z.js.map
2196
+ //# sourceMappingURL=chunk-NIU6J6OX.js.map