@jmruthers/pace-core 0.5.189 → 0.5.191

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (438) hide show
  1. package/core-usage-manifest.json +0 -4
  2. package/dist/{AuthService-B-cd2MA4.d.ts → AuthService-CbP_utw2.d.ts} +7 -3
  3. package/dist/{DataTable-IVYljGJ6.d.ts → DataTable-Be6dH_dR.d.ts} +1 -1
  4. package/dist/{DataTable-GUFUNZ3N.js → DataTable-WKRZD47S.js} +8 -8
  5. package/dist/{PublicPageProvider-B8HaLe69.d.ts → PublicPageProvider-ULXC_u6U.d.ts} +84 -25
  6. package/dist/{UnifiedAuthProvider-BG0AL5eE.d.ts → UnifiedAuthProvider-BYA9qB-o.d.ts} +4 -3
  7. package/dist/{UnifiedAuthProvider-643PUAIM.js → UnifiedAuthProvider-FTSG5XH7.js} +4 -2
  8. package/dist/{api-YP7XD5L6.js → api-IHKALJZD.js} +4 -2
  9. package/dist/{chunk-VGZZXKBR.js → chunk-6LTQQAT6.js} +351 -157
  10. package/dist/chunk-6LTQQAT6.js.map +1 -0
  11. package/dist/{chunk-MX64ZF6I.js → chunk-6TQDD426.js} +15 -15
  12. package/dist/chunk-6TQDD426.js.map +1 -0
  13. package/dist/{chunk-YHCN776L.js → chunk-G37KK66H.js} +2 -75
  14. package/dist/chunk-G37KK66H.js.map +1 -0
  15. package/dist/{chunk-THRPYOFK.js → chunk-HW3OVDUF.js} +5 -5
  16. package/dist/chunk-HW3OVDUF.js.map +1 -0
  17. package/dist/{chunk-F2IMUDXZ.js → chunk-I7PSE6JW.js} +75 -2
  18. package/dist/chunk-I7PSE6JW.js.map +1 -0
  19. package/dist/{chunk-IM4QE42D.js → chunk-LOMZXPSN.js} +141 -326
  20. package/dist/chunk-LOMZXPSN.js.map +1 -0
  21. package/dist/chunk-OETXORNB.js +614 -0
  22. package/dist/chunk-OETXORNB.js.map +1 -0
  23. package/dist/{chunk-HESYZWZW.js → chunk-QWWZ5CAQ.js} +2 -2
  24. package/dist/{chunk-HEHYGYOX.js → chunk-ROXMHMY2.js} +403 -46
  25. package/dist/chunk-ROXMHMY2.js.map +1 -0
  26. package/dist/{chunk-2UUZZJFT.js → chunk-ULHIJK66.js} +228 -177
  27. package/dist/{chunk-2UUZZJFT.js.map → chunk-ULHIJK66.js.map} +1 -1
  28. package/dist/{chunk-YGPFYGA6.js → chunk-VKB2CO4Z.js} +838 -503
  29. package/dist/chunk-VKB2CO4Z.js.map +1 -0
  30. package/dist/{chunk-3GOZZZYH.js → chunk-VRGWKHDB.js} +238 -301
  31. package/dist/chunk-VRGWKHDB.js.map +1 -0
  32. package/dist/{chunk-UCQSRW7Z.js → chunk-XNYQOL3Z.js} +431 -384
  33. package/dist/chunk-XNYQOL3Z.js.map +1 -0
  34. package/dist/{chunk-DDM4CCYT.js → chunk-XYXSXPUK.js} +79 -59
  35. package/dist/chunk-XYXSXPUK.js.map +1 -0
  36. package/dist/{chunk-SAUPYVLF.js → chunk-ZSAAAMVR.js} +1 -1
  37. package/dist/chunk-ZSAAAMVR.js.map +1 -0
  38. package/dist/components.d.ts +5 -6
  39. package/dist/components.js +19 -19
  40. package/dist/components.js.map +1 -1
  41. package/dist/{database.generated-DI89OQeI.d.ts → database.generated-CzIvgcPu.d.ts} +165 -201
  42. package/dist/eslint-rules/pace-core-compliance.cjs +0 -2
  43. package/dist/{file-reference-D037xOFK.d.ts → file-reference-BavO2eQj.d.ts} +13 -10
  44. package/dist/hooks.d.ts +20 -15
  45. package/dist/hooks.js +14 -8
  46. package/dist/hooks.js.map +1 -1
  47. package/dist/index.d.ts +17 -15
  48. package/dist/index.js +86 -81
  49. package/dist/index.js.map +1 -1
  50. package/dist/providers.d.ts +3 -3
  51. package/dist/providers.js +3 -1
  52. package/dist/rbac/index.d.ts +77 -13
  53. package/dist/rbac/index.js +12 -9
  54. package/dist/{types-Bwgl--Xo.d.ts → types-CEpcvwwF.d.ts} +1 -1
  55. package/dist/types.d.ts +3 -3
  56. package/dist/types.js +1 -1
  57. package/dist/{usePublicRouteParams-CTDELQ7H.d.ts → usePublicRouteParams-TZe0gy-4.d.ts} +17 -10
  58. package/dist/utils.d.ts +8 -8
  59. package/dist/utils.js +16 -16
  60. package/docs/README.md +2 -2
  61. package/docs/api/classes/ColumnFactory.md +1 -1
  62. package/docs/api/classes/ErrorBoundary.md +1 -1
  63. package/docs/api/classes/InvalidScopeError.md +2 -2
  64. package/docs/api/classes/Logger.md +1 -1
  65. package/docs/api/classes/MissingUserContextError.md +2 -2
  66. package/docs/api/classes/OrganisationContextRequiredError.md +1 -1
  67. package/docs/api/classes/PermissionDeniedError.md +1 -1
  68. package/docs/api/classes/RBACAuditManager.md +2 -2
  69. package/docs/api/classes/RBACCache.md +1 -1
  70. package/docs/api/classes/RBACEngine.md +5 -5
  71. package/docs/api/classes/RBACError.md +1 -1
  72. package/docs/api/classes/RBACNotInitializedError.md +2 -2
  73. package/docs/api/classes/SecureSupabaseClient.md +25 -20
  74. package/docs/api/classes/StorageUtils.md +7 -4
  75. package/docs/api/enums/FileCategory.md +1 -1
  76. package/docs/api/enums/LogLevel.md +1 -1
  77. package/docs/api/enums/RBACErrorCode.md +1 -1
  78. package/docs/api/enums/RPCFunction.md +1 -1
  79. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  80. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  81. package/docs/api/interfaces/AggregateConfig.md +1 -1
  82. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  83. package/docs/api/interfaces/AvatarProps.md +1 -1
  84. package/docs/api/interfaces/BadgeProps.md +1 -1
  85. package/docs/api/interfaces/ButtonProps.md +1 -1
  86. package/docs/api/interfaces/CalendarProps.md +20 -6
  87. package/docs/api/interfaces/CardProps.md +1 -1
  88. package/docs/api/interfaces/ColorPalette.md +1 -1
  89. package/docs/api/interfaces/ColorShade.md +1 -1
  90. package/docs/api/interfaces/ComplianceResult.md +1 -1
  91. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  92. package/docs/api/interfaces/DataRecord.md +1 -1
  93. package/docs/api/interfaces/DataTableAction.md +1 -1
  94. package/docs/api/interfaces/DataTableColumn.md +1 -1
  95. package/docs/api/interfaces/DataTableProps.md +1 -1
  96. package/docs/api/interfaces/DataTableToolbarButton.md +1 -1
  97. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  98. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  99. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  100. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  101. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  102. package/docs/api/interfaces/ExportColumn.md +1 -1
  103. package/docs/api/interfaces/ExportOptions.md +1 -1
  104. package/docs/api/interfaces/FileDisplayProps.md +62 -16
  105. package/docs/api/interfaces/FileMetadata.md +1 -1
  106. package/docs/api/interfaces/FileReference.md +2 -2
  107. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  108. package/docs/api/interfaces/FileUploadOptions.md +26 -12
  109. package/docs/api/interfaces/FileUploadProps.md +30 -19
  110. package/docs/api/interfaces/FooterProps.md +1 -1
  111. package/docs/api/interfaces/FormFieldProps.md +1 -1
  112. package/docs/api/interfaces/FormProps.md +1 -1
  113. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  114. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  115. package/docs/api/interfaces/InputProps.md +1 -1
  116. package/docs/api/interfaces/LabelProps.md +1 -1
  117. package/docs/api/interfaces/LoggerConfig.md +1 -1
  118. package/docs/api/interfaces/LoginFormProps.md +1 -1
  119. package/docs/api/interfaces/NavigationAccessRecord.md +10 -10
  120. package/docs/api/interfaces/NavigationContextType.md +9 -9
  121. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  122. package/docs/api/interfaces/NavigationItem.md +1 -1
  123. package/docs/api/interfaces/NavigationMenuProps.md +1 -1
  124. package/docs/api/interfaces/NavigationProviderProps.md +7 -7
  125. package/docs/api/interfaces/Organisation.md +1 -1
  126. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  127. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  128. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  129. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  130. package/docs/api/interfaces/PaceAppLayoutProps.md +1 -1
  131. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  132. package/docs/api/interfaces/PageAccessRecord.md +8 -8
  133. package/docs/api/interfaces/PagePermissionContextType.md +8 -8
  134. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  135. package/docs/api/interfaces/PagePermissionProviderProps.md +7 -7
  136. package/docs/api/interfaces/PaletteData.md +1 -1
  137. package/docs/api/interfaces/ParsedAddress.md +2 -2
  138. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  139. package/docs/api/interfaces/ProgressProps.md +3 -11
  140. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  141. package/docs/api/interfaces/PublicPageFooterProps.md +1 -1
  142. package/docs/api/interfaces/PublicPageHeaderProps.md +1 -1
  143. package/docs/api/interfaces/PublicPageLayoutProps.md +1 -1
  144. package/docs/api/interfaces/QuickFix.md +1 -1
  145. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  146. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  147. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  148. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  149. package/docs/api/interfaces/RBACConfig.md +2 -2
  150. package/docs/api/interfaces/RBACContext.md +1 -1
  151. package/docs/api/interfaces/RBACLogger.md +1 -1
  152. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  153. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  154. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  155. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  156. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  157. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  158. package/docs/api/interfaces/RBACResult.md +1 -1
  159. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  160. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  161. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  162. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  163. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  164. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  165. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  166. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  167. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  168. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  169. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  170. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  171. package/docs/api/interfaces/RoleBasedRouterContextType.md +8 -8
  172. package/docs/api/interfaces/RoleBasedRouterProps.md +10 -10
  173. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  174. package/docs/api/interfaces/RouteAccessRecord.md +10 -10
  175. package/docs/api/interfaces/RouteConfig.md +10 -10
  176. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  177. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  178. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  179. package/docs/api/interfaces/SessionRestorationLoaderProps.md +1 -1
  180. package/docs/api/interfaces/SetupIssue.md +1 -1
  181. package/docs/api/interfaces/StorageConfig.md +4 -4
  182. package/docs/api/interfaces/StorageFileInfo.md +7 -7
  183. package/docs/api/interfaces/StorageFileMetadata.md +25 -14
  184. package/docs/api/interfaces/StorageListOptions.md +22 -9
  185. package/docs/api/interfaces/StorageListResult.md +4 -4
  186. package/docs/api/interfaces/StorageUploadOptions.md +21 -8
  187. package/docs/api/interfaces/StorageUploadResult.md +6 -6
  188. package/docs/api/interfaces/StorageUrlOptions.md +19 -6
  189. package/docs/api/interfaces/StyleImport.md +1 -1
  190. package/docs/api/interfaces/SwitchProps.md +1 -1
  191. package/docs/api/interfaces/TabsContentProps.md +1 -1
  192. package/docs/api/interfaces/TabsListProps.md +1 -1
  193. package/docs/api/interfaces/TabsProps.md +1 -1
  194. package/docs/api/interfaces/TabsTriggerProps.md +1 -1
  195. package/docs/api/interfaces/TextareaProps.md +1 -1
  196. package/docs/api/interfaces/ToastActionElement.md +1 -1
  197. package/docs/api/interfaces/ToastProps.md +1 -1
  198. package/docs/api/interfaces/UnifiedAuthContextType.md +53 -53
  199. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  200. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  201. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  202. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  203. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  204. package/docs/api/interfaces/UsePublicEventLogoOptions.md +2 -2
  205. package/docs/api/interfaces/UsePublicEventLogoReturn.md +1 -1
  206. package/docs/api/interfaces/UsePublicEventOptions.md +1 -1
  207. package/docs/api/interfaces/UsePublicEventReturn.md +1 -1
  208. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  209. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  210. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  211. package/docs/api/interfaces/UseResolvedScopeOptions.md +5 -5
  212. package/docs/api/interfaces/UseResolvedScopeReturn.md +4 -4
  213. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  214. package/docs/api/interfaces/UserEventAccess.md +11 -11
  215. package/docs/api/interfaces/UserMenuProps.md +1 -1
  216. package/docs/api/interfaces/UserProfile.md +1 -1
  217. package/docs/api/modules.md +165 -106
  218. package/docs/api-reference/components.md +15 -7
  219. package/docs/api-reference/providers.md +2 -2
  220. package/docs/api-reference/rpc-functions.md +1 -0
  221. package/docs/best-practices/README.md +1 -1
  222. package/docs/best-practices/deployment.md +8 -8
  223. package/docs/getting-started/examples/README.md +2 -2
  224. package/docs/getting-started/installation-guide.md +4 -4
  225. package/docs/getting-started/quick-start.md +3 -3
  226. package/docs/migration/MIGRATION_GUIDE.md +3 -3
  227. package/docs/migration/README.md +18 -0
  228. package/docs/migration/database-changes-december-2025.md +767 -0
  229. package/docs/migration/person-scoped-profiles-migration-guide.md +472 -0
  230. package/docs/rbac/compliance/compliance-guide.md +2 -2
  231. package/docs/rbac/event-based-apps.md +2 -2
  232. package/docs/rbac/getting-started.md +2 -2
  233. package/docs/rbac/quick-start.md +2 -2
  234. package/docs/security/README.md +4 -4
  235. package/docs/standards/07-rbac-and-rls-standard.md +430 -7
  236. package/docs/troubleshooting/README.md +2 -2
  237. package/docs/troubleshooting/migration.md +3 -3
  238. package/package.json +1 -3
  239. package/scripts/check-pace-core-compliance.cjs +1 -1
  240. package/scripts/check-pace-core-compliance.js +1 -1
  241. package/src/__tests__/fixtures/supabase.ts +301 -0
  242. package/src/__tests__/public-recipe-view.test.ts +19 -19
  243. package/src/__tests__/rls-policies.test.ts +210 -74
  244. package/src/components/AddressField/AddressField.test.tsx +42 -0
  245. package/src/components/AddressField/AddressField.tsx +71 -60
  246. package/src/components/AddressField/README.md +7 -6
  247. package/src/components/Alert/Alert.test.tsx +50 -10
  248. package/src/components/Alert/Alert.tsx +5 -3
  249. package/src/components/Avatar/Avatar.test.tsx +95 -43
  250. package/src/components/Avatar/Avatar.tsx +16 -16
  251. package/src/components/Button/Button.test.tsx +2 -1
  252. package/src/components/Button/Button.tsx +3 -3
  253. package/src/components/Calendar/Calendar.test.tsx +53 -37
  254. package/src/components/Calendar/Calendar.tsx +409 -82
  255. package/src/components/Card/Card.test.tsx +7 -4
  256. package/src/components/Card/Card.tsx +3 -6
  257. package/src/components/Checkbox/Checkbox.tsx +2 -2
  258. package/src/components/DataTable/components/ActionButtons.tsx +5 -5
  259. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  260. package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
  261. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
  262. package/src/components/DataTable/components/DataTableBody.tsx +12 -12
  263. package/src/components/DataTable/components/DataTableCore.tsx +3 -3
  264. package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
  265. package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
  266. package/src/components/DataTable/components/EditableRow.tsx +2 -2
  267. package/src/components/DataTable/components/EmptyState.tsx +3 -3
  268. package/src/components/DataTable/components/GroupHeader.tsx +2 -2
  269. package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
  270. package/src/components/DataTable/components/ImportModal.tsx +4 -4
  271. package/src/components/DataTable/components/LoadingState.tsx +1 -1
  272. package/src/components/DataTable/components/PaginationControls.tsx +11 -11
  273. package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
  274. package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
  275. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
  276. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
  277. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
  278. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
  279. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
  280. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
  281. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
  282. package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
  283. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
  284. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
  285. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
  286. package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
  287. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
  288. package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
  289. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
  290. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
  291. package/src/components/Dialog/Dialog.tsx +2 -2
  292. package/src/components/EventSelector/EventSelector.tsx +7 -7
  293. package/src/components/FileDisplay/FileDisplay.tsx +291 -179
  294. package/src/components/FileUpload/FileUpload.tsx +7 -4
  295. package/src/components/Header/Header.test.tsx +28 -0
  296. package/src/components/Header/Header.tsx +22 -9
  297. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
  298. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
  299. package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
  300. package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
  301. package/src/components/OrganisationSelector/OrganisationSelector.tsx +42 -22
  302. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
  303. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
  304. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
  305. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
  306. package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
  307. package/src/components/PaceAppLayout/test-setup.tsx +1 -0
  308. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
  309. package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
  310. package/src/components/Progress/Progress.test.tsx +18 -19
  311. package/src/components/Progress/Progress.tsx +31 -32
  312. package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
  313. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
  314. package/src/components/Select/Select.test.tsx +4 -1
  315. package/src/components/Select/Select.tsx +65 -20
  316. package/src/components/Switch/Switch.test.tsx +2 -1
  317. package/src/components/Switch/Switch.tsx +1 -1
  318. package/src/components/Toast/Toast.tsx +1 -1
  319. package/src/components/Tooltip/Tooltip.test.tsx +8 -2
  320. package/src/components/UserMenu/UserMenu.tsx +3 -3
  321. package/src/eslint-rules/pace-core-compliance.cjs +0 -2
  322. package/src/eslint-rules/pace-core-compliance.js +0 -2
  323. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
  324. package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
  325. package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
  326. package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
  327. package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
  328. package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
  329. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -1
  330. package/src/hooks/__tests__/usePublicEvent.test.ts +608 -0
  331. package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
  332. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +67 -24
  333. package/src/hooks/index.ts +1 -1
  334. package/src/hooks/public/usePublicEvent.ts +10 -10
  335. package/src/hooks/public/usePublicFileDisplay.ts +173 -87
  336. package/src/hooks/useAppConfig.ts +24 -5
  337. package/src/hooks/useFileDisplay.ts +298 -36
  338. package/src/hooks/useFileReference.ts +56 -11
  339. package/src/hooks/useFileUrl.ts +1 -1
  340. package/src/hooks/useInactivityTracker.ts +16 -7
  341. package/src/hooks/usePermissionCache.test.ts +85 -8
  342. package/src/hooks/useQueryCache.ts +27 -6
  343. package/src/hooks/useSecureDataAccess.test.ts +87 -42
  344. package/src/hooks/useSecureDataAccess.ts +95 -48
  345. package/src/providers/__tests__/OrganisationProvider.test.tsx +27 -21
  346. package/src/providers/services/EventServiceProvider.tsx +37 -17
  347. package/src/providers/services/InactivityServiceProvider.tsx +4 -4
  348. package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
  349. package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
  350. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
  351. package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
  352. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
  353. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
  354. package/src/rbac/api.ts +240 -36
  355. package/src/rbac/cache-invalidation.ts +21 -7
  356. package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
  357. package/src/rbac/components/NavigationGuard.tsx +23 -63
  358. package/src/rbac/components/NavigationProvider.test.tsx +52 -23
  359. package/src/rbac/components/NavigationProvider.tsx +13 -11
  360. package/src/rbac/components/PagePermissionGuard.tsx +77 -203
  361. package/src/rbac/components/PagePermissionProvider.tsx +13 -11
  362. package/src/rbac/components/PermissionEnforcer.tsx +24 -62
  363. package/src/rbac/components/RoleBasedRouter.tsx +14 -12
  364. package/src/rbac/components/SecureDataProvider.tsx +13 -11
  365. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
  366. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
  367. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
  368. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
  369. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
  370. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
  371. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
  372. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
  373. package/src/rbac/engine.ts +4 -2
  374. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
  375. package/src/rbac/hooks/index.ts +3 -0
  376. package/src/rbac/hooks/useCan.test.ts +101 -53
  377. package/src/rbac/hooks/usePermissions.ts +108 -41
  378. package/src/rbac/hooks/useRBAC.test.ts +11 -3
  379. package/src/rbac/hooks/useRBAC.ts +83 -40
  380. package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
  381. package/src/rbac/hooks/useResolvedScope.ts +128 -70
  382. package/src/rbac/hooks/useSecureSupabase.ts +36 -19
  383. package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
  384. package/src/rbac/request-deduplication.ts +1 -1
  385. package/src/rbac/secureClient.ts +72 -12
  386. package/src/rbac/security.ts +29 -23
  387. package/src/rbac/types.ts +10 -0
  388. package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
  389. package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
  390. package/src/rbac/utils/__tests__/eventContext.test.ts +8 -3
  391. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +74 -12
  392. package/src/rbac/utils/contextValidator.ts +288 -0
  393. package/src/rbac/utils/eventContext.ts +52 -3
  394. package/src/services/AuthService.ts +37 -8
  395. package/src/services/EventService.ts +165 -21
  396. package/src/services/OrganisationService.ts +125 -137
  397. package/src/services/__tests__/EventService.test.ts +26 -21
  398. package/src/services/__tests__/OrganisationService.pagination.test.ts +34 -8
  399. package/src/services/__tests__/OrganisationService.test.ts +218 -86
  400. package/src/types/database.generated.ts +166 -201
  401. package/src/types/file-reference.ts +13 -10
  402. package/src/types/supabase.ts +2 -2
  403. package/src/utils/__tests__/secureDataAccess.unit.test.ts +3 -2
  404. package/src/utils/app/appNameResolver.test.ts +346 -73
  405. package/src/utils/context/superAdminOverride.ts +58 -0
  406. package/src/utils/file-reference/index.ts +65 -37
  407. package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
  408. package/src/utils/google-places/googlePlacesUtils.ts +1 -1
  409. package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
  410. package/src/utils/google-places/types.ts +1 -1
  411. package/src/utils/request-deduplication.ts +4 -4
  412. package/src/utils/security/secureDataAccess.test.ts +1 -1
  413. package/src/utils/security/secureDataAccess.ts +7 -4
  414. package/src/utils/storage/README.md +1 -1
  415. package/src/utils/storage/helpers.test.ts +1 -1
  416. package/src/utils/storage/helpers.ts +38 -19
  417. package/src/utils/storage/types.ts +15 -8
  418. package/src/utils/validation/__tests__/csrf.test.ts +105 -0
  419. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
  420. package/src/vite-env.d.ts +2 -2
  421. package/dist/chunk-3GOZZZYH.js.map +0 -1
  422. package/dist/chunk-DDM4CCYT.js.map +0 -1
  423. package/dist/chunk-E7UAOUMY.js +0 -75
  424. package/dist/chunk-E7UAOUMY.js.map +0 -1
  425. package/dist/chunk-F2IMUDXZ.js.map +0 -1
  426. package/dist/chunk-HEHYGYOX.js.map +0 -1
  427. package/dist/chunk-IM4QE42D.js.map +0 -1
  428. package/dist/chunk-MX64ZF6I.js.map +0 -1
  429. package/dist/chunk-SAUPYVLF.js.map +0 -1
  430. package/dist/chunk-THRPYOFK.js.map +0 -1
  431. package/dist/chunk-UCQSRW7Z.js.map +0 -1
  432. package/dist/chunk-VGZZXKBR.js.map +0 -1
  433. package/dist/chunk-YGPFYGA6.js.map +0 -1
  434. package/dist/chunk-YHCN776L.js.map +0 -1
  435. /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-WKRZD47S.js.map} +0 -0
  436. /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-FTSG5XH7.js.map} +0 -0
  437. /package/dist/{api-YP7XD5L6.js.map → api-IHKALJZD.js.map} +0 -0
  438. /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
@@ -1,3 +1,7 @@
1
+ import {
2
+ getAppConfigByName,
3
+ isSuperAdmin
4
+ } from "./chunk-ROXMHMY2.js";
1
5
  import {
2
6
  assertOrganisationId,
3
7
  assertUserId
@@ -315,6 +319,8 @@ var AuthService = class extends BaseService {
315
319
  // Lifecycle methods
316
320
  async initialize() {
317
321
  await super.initialize();
322
+ this.authLoading = true;
323
+ this.notify();
318
324
  await this.setupAuthStateListener();
319
325
  await this.restoreSession();
320
326
  }
@@ -420,13 +426,15 @@ var AuthService = class extends BaseService {
420
426
  const hasTimeoutError = this.sessionRestorationState.restorationError?.name === "SessionRestorationTimeoutError";
421
427
  if (this.sessionRestorationState.isRestoring || this.sessionRestorationState.restorationError || hasTimeoutError && session) {
422
428
  this.finishSessionRestoration();
423
- return;
429
+ }
430
+ } else {
431
+ if (this.sessionRestorationState.isRestoring) {
432
+ this.finishSessionRestoration();
424
433
  }
425
434
  }
426
- if (this.sessionRestorationState.isRestoring) {
427
- this.finishSessionRestoration();
428
- return;
429
- }
435
+ this.authLoading = false;
436
+ this.notify();
437
+ return;
430
438
  }
431
439
  this.authLoading = false;
432
440
  this.notify();
@@ -487,7 +495,12 @@ var AuthService = class extends BaseService {
487
495
  this.user = null;
488
496
  this.authError = null;
489
497
  }
490
- this.finishSessionRestoration();
498
+ setTimeout(() => {
499
+ if (this.sessionRestorationState.isRestoring && !this.sessionRestorationState.restorationComplete) {
500
+ logger.debug("AuthService", "INITIAL_SESSION event did not fire, finishing restoration");
501
+ this.finishSessionRestoration();
502
+ }
503
+ }, 100);
491
504
  } catch (error) {
492
505
  const restorationError = error instanceof Error ? error : new Error("Unknown error during auth initialization");
493
506
  logger.error("AuthService", "Error during auth initialization:", restorationError);
@@ -653,6 +666,17 @@ var OrganisationService = class extends BaseService {
653
666
  }
654
667
  // Additional methods for testing
655
668
  setSelectedOrganisation(organisation) {
669
+ if (organisation && this._organisations.length > 0) {
670
+ const isValidOrg = this._organisations.some((org) => org.id === organisation.id);
671
+ if (!isValidOrg) {
672
+ logger.warn("OrganisationService", "Attempted to set invalid organisation - not in user's accessible organisations", {
673
+ organisationId: organisation.id,
674
+ organisationName: organisation.name,
675
+ accessibleOrgIds: this._organisations.map((o) => o.id)
676
+ });
677
+ return;
678
+ }
679
+ }
656
680
  this._selectedOrganisation = organisation;
657
681
  if (organisation) {
658
682
  localStorage.setItem("pace-core-selected-organisation", JSON.stringify(organisation));
@@ -844,118 +868,80 @@ var OrganisationService = class extends BaseService {
844
868
  this._error = null;
845
869
  this.notify();
846
870
  try {
847
- let memberships, membershipError;
871
+ let memberships, membershipError, organisations = [];
848
872
  try {
849
- const timeoutPromise = new Promise((_, reject) => {
850
- const timeoutId = setTimeout(() => reject(new Error("RPC call timeout after 10 seconds")), 1e4);
851
- abortSignal.addEventListener("abort", () => {
852
- clearTimeout(timeoutId);
853
- reject(new Error("Request aborted"));
854
- });
855
- });
856
- const rpcPromise = this.supabaseClient.rpc("data_user_organisation_roles_get", {
857
- p_user_id: this.user.id,
858
- p_organisation_id: null
859
- });
860
873
  if (abortSignal.aborted) {
861
874
  throw new Error("Request aborted");
862
875
  }
863
- const result = await Promise.race([rpcPromise, timeoutPromise]);
864
- memberships = result.data?.filter(
865
- (role) => ["org_admin", "leader", "member", "supporter"].includes(role.role)
866
- ).map((m) => ({
876
+ const { data: rolesData, error: rolesError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
877
+ id,
878
+ user_id,
879
+ organisation_id,
880
+ role,
881
+ status,
882
+ granted_at,
883
+ granted_by,
884
+ revoked_at,
885
+ revoked_by,
886
+ notes,
887
+ created_at,
888
+ updated_at,
889
+ core_organisations!inner(
890
+ id,
891
+ name,
892
+ display_name,
893
+ subscription_tier,
894
+ settings,
895
+ is_active,
896
+ parent_id,
897
+ created_at,
898
+ updated_at
899
+ )
900
+ `).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null);
901
+ if (rolesError) {
902
+ logger.error("OrganisationService", "Error loading organisation roles:", rolesError);
903
+ throw rolesError;
904
+ }
905
+ memberships = rolesData?.map((m) => ({
867
906
  ...m,
868
907
  user_id: assertUserId(m.user_id),
869
908
  organisation_id: assertOrganisationId(m.organisation_id)
870
909
  })) || [];
871
- membershipError = result.error;
872
- } catch (queryError) {
873
- membershipError = queryError instanceof Error ? queryError : new Error(String(queryError));
874
- }
875
- if (membershipError) {
876
- logger.error("OrganisationService", "Error loading memberships:", membershipError);
877
- if (membershipError.message?.includes("timeout")) {
878
- try {
879
- if (abortSignal.aborted) {
880
- throw new Error("Request aborted");
881
- }
882
- const { data: fallbackData, error: fallbackError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
883
- id,
884
- user_id,
885
- organisation_id,
886
- role,
887
- status,
888
- granted_at,
889
- granted_by,
890
- revoked_at,
891
- revoked_by,
892
- notes,
893
- created_at,
894
- updated_at,
895
- organisations!inner(
896
- id,
897
- name,
898
- display_name,
899
- subscription_tier,
900
- settings,
901
- is_active,
902
- parent_id,
903
- created_at,
904
- updated_at
905
- )
906
- `).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null).in("role", ["org_admin", "leader", "member", "supporter"]);
907
- if (fallbackError) {
908
- logger.error("OrganisationService", "Fallback query also failed:", fallbackError);
909
- throw membershipError;
910
- }
911
- memberships = fallbackData?.map((m) => ({
912
- ...m,
913
- user_id: assertUserId(m.user_id),
914
- organisation_id: assertOrganisationId(m.organisation_id)
915
- })) || [];
916
- membershipError = null;
917
- } catch (fallbackErr) {
918
- logger.error("OrganisationService", "Fallback query failed:", fallbackErr);
919
- throw membershipError;
910
+ const organisationsMap = /* @__PURE__ */ new Map();
911
+ rolesData?.forEach((role) => {
912
+ const orgData = role.core_organisations;
913
+ if (orgData && role.organisation_id && !organisationsMap.has(role.organisation_id)) {
914
+ organisationsMap.set(role.organisation_id, {
915
+ id: orgData.id,
916
+ name: orgData.name,
917
+ display_name: orgData.display_name,
918
+ subscription_tier: orgData.subscription_tier,
919
+ settings: orgData.settings,
920
+ is_active: orgData.is_active,
921
+ parent_id: orgData.parent_id,
922
+ created_at: orgData.created_at,
923
+ updated_at: orgData.updated_at
924
+ });
920
925
  }
926
+ });
927
+ organisations = Array.from(organisationsMap.values());
928
+ } catch (queryError) {
929
+ if (queryError instanceof Error) {
930
+ membershipError = queryError;
931
+ } else if (queryError && typeof queryError === "object" && "message" in queryError) {
932
+ membershipError = new Error(String(queryError.message));
921
933
  } else {
922
- throw membershipError;
934
+ membershipError = new Error(String(queryError));
923
935
  }
936
+ logger.error("OrganisationService", "Error loading organisation roles:", membershipError);
937
+ throw membershipError;
924
938
  }
925
939
  if (!memberships || memberships.length === 0) {
926
940
  throw new Error("User has no active organisation memberships");
927
941
  }
928
- const organisationIds = memberships.map((m) => m.organisation_id).filter((id) => {
929
- if (!id || typeof id !== "string") {
930
- logger.warn("OrganisationService", "Invalid organisation ID (not string):", id);
931
- return false;
932
- }
933
- const trimmedId = id.trim();
934
- if (trimmedId === "") {
935
- logger.warn("OrganisationService", "Empty organisation ID found");
936
- return false;
937
- }
938
- const isValidUuid = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(trimmedId);
939
- if (!isValidUuid) {
940
- logger.warn("OrganisationService", "Invalid UUID format:", trimmedId);
941
- }
942
- return isValidUuid;
943
- });
944
- if (organisationIds.length === 0) {
945
- logger.warn("OrganisationService", "No valid organisation IDs found in memberships:", memberships);
946
- throw new Error("No valid organisation IDs found in memberships");
947
- }
948
- if (abortSignal.aborted) {
949
- throw new Error("Request aborted");
950
- }
951
- const { data: allOrganisations, error: orgError } = await this.supabaseClient.from("organisations").select("id, name, display_name, subscription_tier, settings, is_active, parent_id, created_at, updated_at");
952
- if (orgError) {
953
- logger.error("OrganisationService", "Error loading organisations:", orgError);
954
- throw orgError;
942
+ if (!organisations || organisations.length === 0) {
943
+ throw new Error("No organisations found in role data");
955
944
  }
956
- const organisations = allOrganisations?.filter(
957
- (org) => organisationIds.includes(org.id)
958
- ) || [];
959
945
  const roleMap = /* @__PURE__ */ new Map();
960
946
  memberships?.forEach((membership) => {
961
947
  roleMap.set(membership.organisation_id, membership.role);
@@ -980,16 +966,13 @@ var OrganisationService = class extends BaseService {
980
966
  initialOrg = validPersistedOrg;
981
967
  selectionMethod = "persisted";
982
968
  } else {
983
- logger.warn("OrganisationService", "Persisted organisation not found in active orgs, clearing cache");
984
969
  localStorage.removeItem("pace-core-selected-organisation");
985
970
  }
986
971
  } else {
987
- logger.warn("OrganisationService", "Invalid persisted organisation ID, clearing cache");
988
972
  localStorage.removeItem("pace-core-selected-organisation");
989
973
  }
990
974
  }
991
975
  } catch (storageError) {
992
- logger.warn("OrganisationService", "Failed to restore persisted organisation:", storageError);
993
976
  localStorage.removeItem("pace-core-selected-organisation");
994
977
  }
995
978
  if (!initialOrg) {
@@ -1009,17 +992,29 @@ var OrganisationService = class extends BaseService {
1009
992
  if (!initialOrg) {
1010
993
  throw new Error("No valid organisation found for user");
1011
994
  }
995
+ const currentSelectedOrg = this._selectedOrganisation;
996
+ if (currentSelectedOrg && !activeOrgs.some((org) => org.id === currentSelectedOrg.id)) {
997
+ logger.warn("OrganisationService", "Current selected organisation is no longer valid, resetting", {
998
+ invalidOrgId: currentSelectedOrg.id,
999
+ validOrgIds: activeOrgs.map((o) => o.id)
1000
+ });
1001
+ this._selectedOrganisation = null;
1002
+ }
1012
1003
  this._selectedOrganisation = initialOrg;
1013
1004
  localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
1014
1005
  await this.setDatabaseOrganisationContext(initialOrg);
1015
1006
  this.retryCount = 0;
1016
1007
  this.hasFailedRef = false;
1017
1008
  } catch (err) {
1018
- logger.error("OrganisationService", "Failed to load organisations:", err);
1019
- this._error = err;
1009
+ const error = err;
1010
+ if (error.message !== "User has no access to active organisations") {
1011
+ logger.error("OrganisationService", "Failed to load organisations:", err);
1012
+ }
1013
+ this._error = error;
1020
1014
  this.retryCount = this.retryCount + 1;
1021
1015
  this.hasFailedRef = true;
1022
1016
  this.clearAllCachedData();
1017
+ this._isContextReady = true;
1023
1018
  } finally {
1024
1019
  this.isLoadingRef = false;
1025
1020
  this._isLoading = false;
@@ -1058,7 +1053,12 @@ function OrganisationServiceProvider({
1058
1053
  let isMounted = true;
1059
1054
  organisationService.initialize().catch((error) => {
1060
1055
  if (isMounted) {
1061
- logger.error("OrganisationServiceProvider", "Failed to initialize organisation service:", error);
1056
+ const errorMessage = error instanceof Error ? error.message : String(error);
1057
+ if (errorMessage === "User has no access to active organisations") {
1058
+ logger.warn("OrganisationServiceProvider", "User has no active organisations (this is expected for users without organisation access):", error);
1059
+ } else {
1060
+ logger.error("OrganisationServiceProvider", "Failed to initialize organisation service:", error);
1061
+ }
1062
1062
  }
1063
1063
  });
1064
1064
  return () => {
@@ -1095,6 +1095,10 @@ var EventService = class extends BaseService {
1095
1095
  this.appName = "";
1096
1096
  this.selectedOrganisation = null;
1097
1097
  this.setSelectedEventId = null;
1098
+ this.isSuperAdmin = false;
1099
+ // Track super admin status for conditional validation
1100
+ this.appConfig = null;
1101
+ // Cache app config to avoid repeated lookups
1098
1102
  // Internal state management
1099
1103
  this.isInitializedRef = false;
1100
1104
  this.isFetchingRef = false;
@@ -1120,6 +1124,7 @@ var EventService = class extends BaseService {
1120
1124
  const newOrgId = selectedOrganisation?.id;
1121
1125
  const previousUserId = this.user?.id || null;
1122
1126
  const newUserId = user?.id || null;
1127
+ const previousAppName = this.appName;
1123
1128
  if (previousUserId !== newUserId) {
1124
1129
  if (previousUserId !== null) {
1125
1130
  await this.clearEventSelectionForUser(previousUserId);
@@ -1128,6 +1133,9 @@ var EventService = class extends BaseService {
1128
1133
  this.selectedEvent = null;
1129
1134
  this.setSelectedEventId?.(null);
1130
1135
  }
1136
+ this.resetInitialization();
1137
+ this.isInitializedRef = false;
1138
+ this.isFetchingRef = false;
1131
1139
  }
1132
1140
  this.supabaseClient = supabaseClient;
1133
1141
  this.user = user;
@@ -1135,6 +1143,23 @@ var EventService = class extends BaseService {
1135
1143
  this.appName = appName;
1136
1144
  this.selectedOrganisation = selectedOrganisation;
1137
1145
  this.setSelectedEventId = setSelectedEventId;
1146
+ if (previousAppName !== appName) {
1147
+ this.appConfig = null;
1148
+ }
1149
+ if (user?.id) {
1150
+ try {
1151
+ this.isSuperAdmin = await isSuperAdmin(user.id);
1152
+ logger.debug("EventService", "Updated super admin status", {
1153
+ userId: user.id,
1154
+ isSuperAdmin: this.isSuperAdmin
1155
+ });
1156
+ } catch (error) {
1157
+ logger.warn("EventService", "Failed to check super admin status", { error });
1158
+ this.isSuperAdmin = false;
1159
+ }
1160
+ } else {
1161
+ this.isSuperAdmin = false;
1162
+ }
1138
1163
  if (previousOrgId !== newOrgId) {
1139
1164
  this.resetInitialization();
1140
1165
  this.isInitializedRef = false;
@@ -1165,18 +1190,6 @@ var EventService = class extends BaseService {
1165
1190
  // Event methods
1166
1191
  setSelectedEvent(event) {
1167
1192
  if (event) {
1168
- try {
1169
- if (this.selectedOrganisation && event.organisation_id !== this.selectedOrganisation.id) {
1170
- logger.error("EventService", "Event organisation_id does not match selected organisation", {
1171
- eventOrganisationId: event.organisation_id,
1172
- selectedOrganisationId: this.selectedOrganisation.id,
1173
- eventName: event.event_name
1174
- });
1175
- return;
1176
- }
1177
- } catch (error) {
1178
- logger.error("EventService", "Error during event validation:", error);
1179
- }
1180
1193
  this.selectedEvent = event;
1181
1194
  this.setSelectedEventId?.(event.event_id);
1182
1195
  this.persistEventSelection(event.event_id).catch((error) => {
@@ -1273,16 +1286,31 @@ var EventService = class extends BaseService {
1273
1286
  }
1274
1287
  // Lifecycle methods
1275
1288
  async initialize() {
1289
+ logger.debug("EventService", "initialize() called", {
1290
+ isInitializedRef: this.isInitializedRef,
1291
+ hasUser: !!this.user,
1292
+ hasSession: !!this.session,
1293
+ appName: this.appName
1294
+ });
1276
1295
  await super.initialize();
1277
1296
  }
1278
1297
  cleanup() {
1279
1298
  super.cleanup();
1280
1299
  }
1281
1300
  async doInitialize() {
1301
+ logger.debug("EventService", "doInitialize() called", {
1302
+ isInitializedRef: this.isInitializedRef,
1303
+ isFetchingRef: this.isFetchingRef,
1304
+ hasUser: !!this.user,
1305
+ hasSession: !!this.session,
1306
+ appName: this.appName
1307
+ });
1282
1308
  if (this.isInitializedRef) {
1309
+ logger.debug("EventService", "Skipping initialization - already initialized");
1283
1310
  return;
1284
1311
  }
1285
1312
  if (this.isFetchingRef) {
1313
+ logger.debug("EventService", "Skipping initialization - already fetching");
1286
1314
  return;
1287
1315
  }
1288
1316
  try {
@@ -1292,31 +1320,107 @@ var EventService = class extends BaseService {
1292
1320
  } catch (error) {
1293
1321
  logger.warn("EventService", "Failed to clean up old storage keys:", error);
1294
1322
  }
1295
- if (!this.user || !this.selectedOrganisation) {
1323
+ if (!this.user) {
1324
+ logger.debug("EventService", "Skipping initialization - missing user");
1296
1325
  return;
1297
1326
  }
1327
+ logger.debug("EventService", "Initializing - fetching events", {
1328
+ userId: this.user.id,
1329
+ organisationId: this.selectedOrganisation?.id || "derived-from-event",
1330
+ appName: this.appName
1331
+ });
1298
1332
  await this.fetchEvents(false);
1333
+ this.isInitializedRef = true;
1299
1334
  }
1300
1335
  doCleanup() {
1301
1336
  }
1302
1337
  async fetchEvents(skipLoadPersisted = false) {
1303
- if (!this.user || !this.session || !this.supabaseClient || !this.appName || !this.selectedOrganisation) {
1338
+ if (!this.user || !this.session || !this.supabaseClient || !this.appName) {
1339
+ logger.debug("EventService", "Skipping fetchEvents - missing dependencies", {
1340
+ hasUser: !!this.user,
1341
+ hasSession: !!this.session,
1342
+ hasSupabaseClient: !!this.supabaseClient,
1343
+ appName: this.appName
1344
+ });
1304
1345
  this.notify();
1305
1346
  return;
1306
1347
  }
1307
1348
  this._isLoading = true;
1308
1349
  this.notify();
1309
1350
  if (this.isFetchingRef) {
1351
+ logger.debug("EventService", "Skipping fetchEvents - already fetching");
1310
1352
  return;
1311
1353
  }
1312
1354
  this.isFetchingRef = true;
1313
1355
  let isMounted = true;
1314
1356
  try {
1315
- const { data, error: rpcError } = await this.supabaseClient.rpc("data_user_events_get", {
1357
+ if (!this.appConfig && this.appName) {
1358
+ try {
1359
+ this.appConfig = await getAppConfigByName(this.appName);
1360
+ } catch (configError) {
1361
+ logger.warn("EventService", "Failed to load app config, defaulting to event-required", {
1362
+ error: configError
1363
+ });
1364
+ this.appConfig = { requires_event: true };
1365
+ }
1366
+ }
1367
+ let organisationIdForRpc = null;
1368
+ let userIsSuperAdmin = false;
1369
+ try {
1370
+ userIsSuperAdmin = await isSuperAdmin(this.user.id);
1371
+ if (userIsSuperAdmin) {
1372
+ organisationIdForRpc = null;
1373
+ logger.debug("EventService", "Super admin detected - fetching all events", {
1374
+ userId: this.user.id
1375
+ });
1376
+ } else {
1377
+ if (this.selectedEvent) {
1378
+ organisationIdForRpc = this.selectedEvent.organisation_id;
1379
+ } else if (this.appConfig?.requires_event === true) {
1380
+ organisationIdForRpc = null;
1381
+ logger.debug("EventService", "Event-required app: fetching all accessible events (no event selected yet)", {
1382
+ userId: this.user.id,
1383
+ appName: this.appName
1384
+ });
1385
+ } else if (this.selectedOrganisation) {
1386
+ organisationIdForRpc = this.selectedOrganisation.id;
1387
+ } else {
1388
+ logger.warn("EventService", "No organisation context available for event fetch", {
1389
+ hasSelectedEvent: !!this.selectedEvent,
1390
+ hasSelectedOrganisation: !!this.selectedOrganisation,
1391
+ appRequiresEvent: this.appConfig?.requires_event
1392
+ });
1393
+ organisationIdForRpc = null;
1394
+ }
1395
+ }
1396
+ } catch (superAdminCheckError) {
1397
+ logger.warn("EventService", "Failed to check super admin status, using organisation-scoped query", {
1398
+ error: superAdminCheckError
1399
+ });
1400
+ if (this.selectedEvent) {
1401
+ organisationIdForRpc = this.selectedEvent.organisation_id;
1402
+ } else if (this.appConfig?.requires_event === true) {
1403
+ organisationIdForRpc = null;
1404
+ } else if (this.selectedOrganisation) {
1405
+ organisationIdForRpc = this.selectedOrganisation.id;
1406
+ }
1407
+ }
1408
+ logger.debug("EventService", "Fetching events via RPC", {
1409
+ userId: this.user.id,
1410
+ organisationId: organisationIdForRpc,
1411
+ appName: this.appName
1412
+ });
1413
+ let { data, error: rpcError } = await this.supabaseClient.rpc("data_user_events_get", {
1316
1414
  p_user_id: this.user.id,
1317
- p_organisation_id: this.selectedOrganisation.id,
1415
+ p_organisation_id: organisationIdForRpc,
1318
1416
  p_app_name: this.appName
1319
1417
  });
1418
+ logger.debug("EventService", "RPC response received", {
1419
+ hasData: !!data,
1420
+ dataLength: Array.isArray(data) ? data.length : "not array",
1421
+ hasError: !!rpcError,
1422
+ error: rpcError
1423
+ });
1320
1424
  if (rpcError) {
1321
1425
  logger.error("EventService", "RPC error fetching events:", rpcError);
1322
1426
  throw new Error(rpcError.message || "Failed to fetch events");
@@ -1428,24 +1532,41 @@ function EventServiceProvider({
1428
1532
  setSelectedEventId
1429
1533
  }) {
1430
1534
  const eventServiceRef = useRef2(null);
1535
+ const initializingRef = useRef2(false);
1431
1536
  if (!eventServiceRef.current) {
1432
1537
  eventServiceRef.current = new EventService(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
1433
1538
  }
1434
1539
  const eventService = eventServiceRef.current;
1435
1540
  useEffect3(() => {
1436
1541
  let isMounted = true;
1542
+ if (initializingRef.current) {
1543
+ return;
1544
+ }
1437
1545
  const updateAndInitialize = async () => {
1438
- await eventService.updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
1439
- if (!isMounted) return;
1440
- await eventService.initialize().catch((error) => {
1441
- if (isMounted) {
1442
- logger.error("EventServiceProvider", "Failed to initialize event service:", error);
1443
- }
1444
- });
1546
+ initializingRef.current = true;
1547
+ try {
1548
+ logger.debug("EventServiceProvider", "Updating dependencies and initializing", {
1549
+ hasUser: !!user,
1550
+ hasSession: !!session,
1551
+ appName,
1552
+ hasSelectedOrganisation: !!selectedOrganisation,
1553
+ organisationId: selectedOrganisation?.id
1554
+ });
1555
+ await eventService.updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
1556
+ if (!isMounted) return;
1557
+ await eventService.initialize().catch((error) => {
1558
+ if (isMounted) {
1559
+ logger.error("EventServiceProvider", "Failed to initialize event service:", error);
1560
+ }
1561
+ });
1562
+ } finally {
1563
+ initializingRef.current = false;
1564
+ }
1445
1565
  };
1446
1566
  updateAndInitialize();
1447
1567
  return () => {
1448
1568
  isMounted = false;
1569
+ initializingRef.current = false;
1449
1570
  };
1450
1571
  }, [supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId]);
1451
1572
  useEffect3(() => {
@@ -1750,8 +1871,10 @@ function InactivityServiceProvider({
1750
1871
  supabaseClient,
1751
1872
  user,
1752
1873
  session,
1753
- idleTimeoutMs = 30 * 60 * 1e3,
1754
- warnBeforeMs = 60 * 1e3,
1874
+ idleTimeoutMs,
1875
+ // REQUIRED: No default - must be explicitly provided
1876
+ warnBeforeMs,
1877
+ // REQUIRED: No default - must be explicitly provided
1755
1878
  onIdleLogout
1756
1879
  }) {
1757
1880
  const inactivityServiceRef = useRef3(null);
@@ -1810,6 +1933,29 @@ function useOrganisationService() {
1810
1933
  return context.organisationService;
1811
1934
  }
1812
1935
 
1936
+ // src/hooks/useOrganisations.ts
1937
+ function useOrganisations() {
1938
+ const organisationService = useOrganisationService();
1939
+ const selectedOrg = organisationService.getSelectedOrganisation();
1940
+ return {
1941
+ selectedOrganisation: selectedOrg,
1942
+ organisations: organisationService.getOrganisations(),
1943
+ userMemberships: organisationService.getUserMemberships(),
1944
+ isLoading: organisationService.isLoading(),
1945
+ error: organisationService.getError(),
1946
+ hasValidOrganisationContext: organisationService.hasValidOrganisationContext(),
1947
+ isContextReady: organisationService.isContextReady(),
1948
+ setSelectedOrganisation: (org) => organisationService.setSelectedOrganisation(org),
1949
+ switchOrganisation: (orgId) => organisationService.switchOrganisation(orgId),
1950
+ getUserRole: (orgId) => organisationService.getUserRole(orgId),
1951
+ validateOrganisationAccess: (orgId) => organisationService.validateOrganisationAccess(orgId),
1952
+ refreshOrganisations: () => organisationService.refreshOrganisations(),
1953
+ ensureOrganisationContext: () => organisationService.ensureOrganisationContext(),
1954
+ isOrganisationSecure: () => organisationService.isOrganisationSecure(),
1955
+ getPrimaryOrganisation: () => organisationService.getPrimaryOrganisation()
1956
+ };
1957
+ }
1958
+
1813
1959
  // src/hooks/services/useEventService.ts
1814
1960
  import { useContext as useContext3, useReducer as useReducer3, useEffect as useEffect7 } from "react";
1815
1961
  function useEventService() {
@@ -1893,6 +2039,7 @@ function UnifiedAuthContextProvider({
1893
2039
  appName,
1894
2040
  appConfig = { requires_event: true },
1895
2041
  // Default to requiring events
2042
+ supabaseClient: supabaseClientProp,
1896
2043
  ...props
1897
2044
  }) {
1898
2045
  const authService = useAuthService();
@@ -1932,15 +2079,31 @@ function UnifiedAuthContextProvider({
1932
2079
  const currentUser = authService.getUser();
1933
2080
  const currentSession = authService.getSession();
1934
2081
  const isAuth = !!(currentUser && currentSession);
1935
- const supabase = authService.getSupabaseClient();
2082
+ const supabase = useMemo6(() => supabaseClientProp, [supabaseClientProp]);
1936
2083
  const [appId, setAppId] = useState3(void 0);
1937
2084
  const isResolvingAppIdRef = useRef4(false);
2085
+ const resolvedAppIdRef = useRef4(void 0);
2086
+ const resolvedUserIdRef = useRef4(void 0);
1938
2087
  useEffect10(() => {
1939
- if (isAuth && currentUser?.id && supabase && appName && !appId && !isResolvingAppIdRef.current) {
2088
+ if (!isAuth) {
2089
+ resolvedAppIdRef.current = void 0;
2090
+ resolvedUserIdRef.current = void 0;
2091
+ setAppId(void 0);
2092
+ return;
2093
+ }
2094
+ if (currentUser?.id && resolvedUserIdRef.current && resolvedUserIdRef.current !== currentUser.id) {
2095
+ resolvedAppIdRef.current = void 0;
2096
+ resolvedUserIdRef.current = void 0;
2097
+ setAppId(void 0);
2098
+ }
2099
+ const currentUserId = currentUser?.id;
2100
+ if (isAuth && currentUserId && supabase && appName && resolvedUserIdRef.current !== currentUserId && // Haven't resolved for this user yet
2101
+ !isResolvingAppIdRef.current) {
1940
2102
  isResolvingAppIdRef.current = true;
1941
- const userId = currentUser.id;
2103
+ resolvedUserIdRef.current = currentUserId;
2104
+ const userId = currentUserId;
1942
2105
  const appNameValue = appName;
1943
- import("./api-YP7XD5L6.js").then(async ({ resolveAppContext, setupRBAC }) => {
2106
+ import("./api-IHKALJZD.js").then(async ({ resolveAppContext, setupRBAC }) => {
1944
2107
  try {
1945
2108
  setupRBAC(supabase);
1946
2109
  const result = await resolveAppContext({
@@ -1948,11 +2111,14 @@ function UnifiedAuthContextProvider({
1948
2111
  appName: appNameValue
1949
2112
  });
1950
2113
  if (result?.appId) {
2114
+ resolvedAppIdRef.current = result.appId;
1951
2115
  setAppId(result.appId);
1952
2116
  logger.debug("UnifiedAuthProvider", "appId resolved on login", {
1953
2117
  appId: result.appId,
1954
2118
  appName: appNameValue
1955
2119
  });
2120
+ } else {
2121
+ resolvedUserIdRef.current = void 0;
1956
2122
  }
1957
2123
  } catch (error) {
1958
2124
  logger.error("UnifiedAuthProvider", "Failed to resolve appId on login", {
@@ -1960,41 +2126,64 @@ function UnifiedAuthContextProvider({
1960
2126
  appName: appNameValue,
1961
2127
  userId
1962
2128
  });
2129
+ resolvedUserIdRef.current = void 0;
1963
2130
  } finally {
1964
2131
  isResolvingAppIdRef.current = false;
1965
2132
  }
1966
2133
  }).catch((importError) => {
1967
2134
  logger.error("UnifiedAuthProvider", "Failed to import RBAC API", importError);
1968
2135
  isResolvingAppIdRef.current = false;
2136
+ resolvedUserIdRef.current = void 0;
1969
2137
  });
1970
2138
  }
1971
- if (!isAuth) {
1972
- setAppId(void 0);
1973
- }
1974
- }, [isAuth, currentUser?.id, supabase, appName, appId]);
2139
+ }, [isAuth, currentUser?.id, supabase, appName]);
1975
2140
  const [, forceUpdate] = useReducer5((x) => x + 1, 0);
2141
+ const forceUpdateTimeoutRef = useRef4(null);
2142
+ const debouncedForceUpdate = useCallback(() => {
2143
+ if (forceUpdateTimeoutRef.current) {
2144
+ clearTimeout(forceUpdateTimeoutRef.current);
2145
+ }
2146
+ forceUpdateTimeoutRef.current = setTimeout(() => {
2147
+ forceUpdate();
2148
+ forceUpdateTimeoutRef.current = null;
2149
+ }, 0);
2150
+ }, [forceUpdate]);
2151
+ const authServiceRef = useRef4(authService);
2152
+ const organisationServiceRef = useRef4(organisationService);
2153
+ const eventServiceRef = useRef4(eventService);
2154
+ const inactivityServiceRef = useRef4(inactivityService);
1976
2155
  useEffect10(() => {
1977
- const unsubscribeAuth = authService.subscribe(() => forceUpdate());
1978
- const unsubscribeOrg = organisationService.subscribe(() => forceUpdate());
1979
- const unsubscribeEvent = eventService.subscribe(() => forceUpdate());
1980
- const unsubscribeInactivity = inactivityService.subscribe(() => forceUpdate());
2156
+ authServiceRef.current = authService;
2157
+ organisationServiceRef.current = organisationService;
2158
+ eventServiceRef.current = eventService;
2159
+ inactivityServiceRef.current = inactivityService;
2160
+ }, [authService, organisationService, eventService, inactivityService]);
2161
+ useEffect10(() => {
2162
+ const unsubscribeAuth = authServiceRef.current.subscribe(debouncedForceUpdate);
2163
+ const unsubscribeOrg = organisationServiceRef.current.subscribe(debouncedForceUpdate);
2164
+ const unsubscribeEvent = eventServiceRef.current.subscribe(debouncedForceUpdate);
2165
+ const unsubscribeInactivity = inactivityServiceRef.current.subscribe(debouncedForceUpdate);
1981
2166
  return () => {
1982
2167
  unsubscribeAuth();
1983
2168
  unsubscribeOrg();
1984
2169
  unsubscribeEvent();
1985
2170
  unsubscribeInactivity();
2171
+ if (forceUpdateTimeoutRef.current) {
2172
+ clearTimeout(forceUpdateTimeoutRef.current);
2173
+ }
1986
2174
  };
1987
- }, [authService, organisationService, eventService, inactivityService]);
2175
+ }, [debouncedForceUpdate]);
1988
2176
  const authLoading = authService.isLoading();
1989
2177
  const orgLoading = organisationService.isLoading();
1990
2178
  const eventLoading = eventService.isLoading();
1991
2179
  const restorationLoading = sessionRestoration.isRestoring && !sessionRestorationTimedOut && !sessionRestoration.restorationError;
1992
2180
  const totalLoading = restorationLoading || authLoading || orgLoading || eventLoading;
1993
2181
  const authError = authService.getError();
1994
- const selectedOrganisation = organisationService.getSelectedOrganisation();
2182
+ const rawSelectedOrganisation = organisationService.getSelectedOrganisation();
1995
2183
  const organisations = organisationService.getOrganisations();
1996
2184
  const userMemberships = organisationService.getUserMemberships();
1997
2185
  const organisationError = organisationService.getError();
2186
+ const selectedOrganisation = appConfig?.requires_event ? null : rawSelectedOrganisation;
1998
2187
  const hasValidOrganisationContext = organisationService.hasValidOrganisationContext();
1999
2188
  const isContextReady = organisationService.isContextReady();
2000
2189
  const events = eventService.getEvents();
@@ -2170,10 +2359,13 @@ function EventServiceProviderWrapper({
2170
2359
  supabaseClient,
2171
2360
  user,
2172
2361
  session,
2173
- appName
2362
+ appName,
2363
+ appConfig
2174
2364
  }) {
2175
- const organisationService = useOrganisationService();
2176
- const selectedOrganisation = organisationService.getSelectedOrganisation();
2365
+ const { selectedOrganisation: rawSelectedOrganisation } = useOrganisations();
2366
+ const selectedOrganisation = appConfig?.requires_event ? null : rawSelectedOrganisation;
2367
+ const setSelectedEventId = useCallback(() => {
2368
+ }, []);
2177
2369
  return /* @__PURE__ */ jsx5(
2178
2370
  EventServiceProvider,
2179
2371
  {
@@ -2182,8 +2374,7 @@ function EventServiceProviderWrapper({
2182
2374
  session,
2183
2375
  appName,
2184
2376
  selectedOrganisation,
2185
- setSelectedEventId: () => {
2186
- },
2377
+ setSelectedEventId,
2187
2378
  children
2188
2379
  }
2189
2380
  );
@@ -2216,6 +2407,7 @@ function ServiceAwareProviders({
2216
2407
  user: authService.getUser(),
2217
2408
  session: authService.getSession(),
2218
2409
  appName,
2410
+ appConfig,
2219
2411
  children: /* @__PURE__ */ jsx5(
2220
2412
  InactivityServiceProvider,
2221
2413
  {
@@ -2258,11 +2450,12 @@ function UnifiedAuthProvider({
2258
2450
  persistState = true,
2259
2451
  enablePersistence,
2260
2452
  requireOrganisationContext = true,
2261
- idleTimeoutMs = 30 * 60 * 1e3,
2262
- // 30 minutes
2263
- warnBeforeMs = 60 * 1e3,
2264
- // 60 seconds
2453
+ idleTimeoutMs,
2454
+ // REQUIRED: No default - must be explicitly provided
2455
+ warnBeforeMs,
2456
+ // REQUIRED: No default - must be explicitly provided
2265
2457
  onIdleLogout,
2458
+ // REQUIRED: No default - must be explicitly provided
2266
2459
  renderInactivityWarning,
2267
2460
  dangerouslyDisableInactivity = false
2268
2461
  }) {
@@ -2307,6 +2500,7 @@ export {
2307
2500
  InactivityServiceProvider,
2308
2501
  useAuthService,
2309
2502
  useOrganisationService,
2503
+ useOrganisations,
2310
2504
  useEventService,
2311
2505
  useInactivityService,
2312
2506
  useSessionRestoration,
@@ -2314,4 +2508,4 @@ export {
2314
2508
  useUnifiedAuth,
2315
2509
  UnifiedAuthProvider
2316
2510
  };
2317
- //# sourceMappingURL=chunk-VGZZXKBR.js.map
2511
+ //# sourceMappingURL=chunk-6LTQQAT6.js.map