@jmruthers/pace-core 0.5.188 → 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 (424) 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-DrLDztHt.d.ts → PublicPageProvider-C4uxosp6.d.ts} +129 -40
  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-UNOTYLQF.js → chunk-NIU6J6OX.js} +772 -725
  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-IPCH26AG.js → chunk-STYK4OH2.js} +11 -11
  30. package/dist/chunk-STYK4OH2.js.map +1 -0
  31. package/dist/{chunk-EFCLXK7F.js → chunk-VVBAW5A5.js} +4201 -3809
  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 -5
  38. package/dist/components.js +19 -23
  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 -12
  46. package/dist/index.js +79 -73
  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 +128 -0
  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 +155 -135
  214. package/docs/api-reference/components.md +72 -29
  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 -4
  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 +252 -226
  243. package/src/components/Avatar/Avatar.tsx +179 -53
  244. package/src/components/Avatar/index.ts +1 -1
  245. package/src/components/Button/Button.test.tsx +2 -1
  246. package/src/components/Button/Button.tsx +3 -3
  247. package/src/components/Calendar/Calendar.test.tsx +53 -37
  248. package/src/components/Calendar/Calendar.tsx +409 -82
  249. package/src/components/Card/Card.test.tsx +7 -4
  250. package/src/components/Card/Card.tsx +3 -6
  251. package/src/components/Checkbox/Checkbox.tsx +2 -2
  252. package/src/components/DataTable/components/ActionButtons.tsx +5 -5
  253. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  254. package/src/components/DataTable/components/ColumnFilter.tsx +1 -1
  255. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +3 -3
  256. package/src/components/DataTable/components/DataTableBody.tsx +12 -12
  257. package/src/components/DataTable/components/DataTableCore.tsx +3 -3
  258. package/src/components/DataTable/components/DataTableToolbar.tsx +5 -5
  259. package/src/components/DataTable/components/DraggableColumnHeader.tsx +3 -3
  260. package/src/components/DataTable/components/EditableRow.tsx +2 -2
  261. package/src/components/DataTable/components/EmptyState.tsx +3 -3
  262. package/src/components/DataTable/components/GroupHeader.tsx +2 -2
  263. package/src/components/DataTable/components/GroupingDropdown.tsx +1 -1
  264. package/src/components/DataTable/components/ImportModal.tsx +4 -4
  265. package/src/components/DataTable/components/LoadingState.tsx +1 -1
  266. package/src/components/DataTable/components/PaginationControls.tsx +11 -11
  267. package/src/components/DataTable/components/UnifiedTableBody.tsx +9 -9
  268. package/src/components/DataTable/components/ViewRowModal.tsx +2 -2
  269. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +11 -37
  270. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +157 -0
  271. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +2 -1
  272. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +128 -0
  273. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +19 -0
  274. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +51 -0
  275. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +84 -0
  276. package/src/components/DataTable/core/__tests__/DataManager.test.ts +14 -0
  277. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +136 -0
  278. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +16 -0
  279. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +18 -0
  280. package/src/components/DataTable/hooks/useDataTablePermissions.ts +28 -7
  281. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +30 -1
  282. package/src/components/DataTable/utils/hierarchicalUtils.ts +38 -10
  283. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -3
  284. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +4 -4
  285. package/src/components/Dialog/Dialog.tsx +2 -2
  286. package/src/components/EventSelector/EventSelector.tsx +7 -7
  287. package/src/components/FileDisplay/FileDisplay.tsx +291 -179
  288. package/src/components/FileUpload/FileUpload.tsx +7 -4
  289. package/src/components/Header/Header.test.tsx +28 -0
  290. package/src/components/Header/Header.tsx +22 -9
  291. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -2
  292. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +19 -14
  293. package/src/components/LoadingSpinner/LoadingSpinner.tsx +5 -5
  294. package/src/components/NavigationMenu/NavigationMenu.test.tsx +127 -1
  295. package/src/components/OrganisationSelector/OrganisationSelector.tsx +8 -8
  296. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +4 -0
  297. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +3 -0
  298. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +3 -0
  299. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +16 -6
  300. package/src/components/PaceAppLayout/PaceAppLayout.tsx +37 -3
  301. package/src/components/PaceAppLayout/test-setup.tsx +1 -0
  302. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +66 -45
  303. package/src/components/PaceLoginPage/PaceLoginPage.tsx +6 -4
  304. package/src/components/Progress/Progress.test.tsx +18 -19
  305. package/src/components/Progress/Progress.tsx +31 -32
  306. package/src/components/PublicLayout/PublicLayout.test.tsx +6 -6
  307. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -3
  308. package/src/components/Select/Select.tsx +5 -5
  309. package/src/components/Switch/Switch.test.tsx +2 -1
  310. package/src/components/Switch/Switch.tsx +1 -1
  311. package/src/components/Toast/Toast.tsx +1 -1
  312. package/src/components/Tooltip/Tooltip.test.tsx +8 -2
  313. package/src/components/UserMenu/UserMenu.test.tsx +7 -9
  314. package/src/components/UserMenu/UserMenu.tsx +10 -8
  315. package/src/components/index.ts +2 -1
  316. package/src/eslint-rules/pace-core-compliance.cjs +0 -2
  317. package/src/eslint-rules/pace-core-compliance.js +0 -2
  318. package/src/hooks/__tests__/hooks.integration.test.tsx +4 -1
  319. package/src/hooks/__tests__/useAppConfig.unit.test.ts +76 -5
  320. package/src/hooks/__tests__/useDataTableState.test.ts +76 -0
  321. package/src/hooks/__tests__/useFileUrl.unit.test.ts +25 -69
  322. package/src/hooks/__tests__/useFileUrlCache.test.ts +129 -0
  323. package/src/hooks/__tests__/usePreventTabReload.test.ts +88 -0
  324. package/src/hooks/__tests__/{usePublicEvent.unit.test.ts → usePublicEvent.test.ts} +28 -1
  325. package/src/hooks/__tests__/useQueryCache.test.ts +144 -0
  326. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +58 -16
  327. package/src/hooks/index.ts +1 -1
  328. package/src/hooks/public/usePublicEvent.ts +2 -2
  329. package/src/hooks/public/usePublicFileDisplay.ts +173 -87
  330. package/src/hooks/useAppConfig.ts +24 -5
  331. package/src/hooks/useFileDisplay.ts +297 -34
  332. package/src/hooks/useFileReference.ts +56 -11
  333. package/src/hooks/useFileUrl.ts +1 -1
  334. package/src/hooks/useInactivityTracker.ts +16 -7
  335. package/src/hooks/usePermissionCache.test.ts +85 -8
  336. package/src/hooks/useQueryCache.ts +21 -0
  337. package/src/hooks/useSecureDataAccess.test.ts +80 -35
  338. package/src/hooks/useSecureDataAccess.ts +80 -37
  339. package/src/index.ts +2 -1
  340. package/src/providers/services/EventServiceProvider.tsx +37 -17
  341. package/src/providers/services/InactivityServiceProvider.tsx +4 -4
  342. package/src/providers/services/OrganisationServiceProvider.tsx +8 -1
  343. package/src/providers/services/UnifiedAuthProvider.tsx +115 -29
  344. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +451 -0
  345. package/src/rbac/__tests__/engine.comprehensive.test.ts +12 -0
  346. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +8 -0
  347. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +4 -0
  348. package/src/rbac/api.ts +240 -36
  349. package/src/rbac/cache-invalidation.ts +21 -7
  350. package/src/rbac/compliance/quick-fix-suggestions.ts +1 -1
  351. package/src/rbac/components/NavigationGuard.tsx +23 -63
  352. package/src/rbac/components/NavigationProvider.test.tsx +52 -23
  353. package/src/rbac/components/NavigationProvider.tsx +13 -11
  354. package/src/rbac/components/PagePermissionGuard.tsx +77 -203
  355. package/src/rbac/components/PagePermissionProvider.tsx +13 -11
  356. package/src/rbac/components/PermissionEnforcer.tsx +24 -62
  357. package/src/rbac/components/RoleBasedRouter.tsx +14 -12
  358. package/src/rbac/components/SecureDataProvider.tsx +13 -11
  359. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +104 -41
  360. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +49 -12
  361. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +22 -1
  362. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +161 -82
  363. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +22 -1
  364. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +77 -30
  365. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +39 -5
  366. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +47 -4
  367. package/src/rbac/engine.ts +4 -2
  368. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +144 -52
  369. package/src/rbac/hooks/index.ts +3 -0
  370. package/src/rbac/hooks/useCan.test.ts +101 -53
  371. package/src/rbac/hooks/usePermissions.ts +108 -41
  372. package/src/rbac/hooks/useRBAC.test.ts +11 -3
  373. package/src/rbac/hooks/useRBAC.ts +83 -40
  374. package/src/rbac/hooks/useResolvedScope.test.ts +189 -63
  375. package/src/rbac/hooks/useResolvedScope.ts +128 -70
  376. package/src/rbac/hooks/useSecureSupabase.ts +36 -19
  377. package/src/rbac/hooks/useSuperAdminBypass.ts +126 -0
  378. package/src/rbac/request-deduplication.ts +1 -1
  379. package/src/rbac/secureClient.ts +72 -12
  380. package/src/rbac/security.ts +29 -23
  381. package/src/rbac/types.ts +10 -0
  382. package/src/rbac/utils/__tests__/contextValidator.test.ts +150 -0
  383. package/src/rbac/utils/__tests__/deep-equal.test.ts +53 -0
  384. package/src/rbac/utils/__tests__/eventContext.test.ts +6 -1
  385. package/src/rbac/utils/contextValidator.ts +288 -0
  386. package/src/rbac/utils/eventContext.ts +48 -2
  387. package/src/services/EventService.ts +165 -21
  388. package/src/services/OrganisationService.ts +37 -2
  389. package/src/services/__tests__/EventService.test.ts +26 -21
  390. package/src/types/file-reference.ts +13 -10
  391. package/src/utils/app/appNameResolver.test.ts +346 -73
  392. package/src/utils/context/superAdminOverride.ts +58 -0
  393. package/src/utils/file-reference/index.ts +61 -33
  394. package/src/utils/google-places/googlePlacesUtils.test.ts +98 -0
  395. package/src/utils/google-places/loadGoogleMapsScript.test.ts +83 -0
  396. package/src/utils/storage/helpers.test.ts +1 -1
  397. package/src/utils/storage/helpers.ts +38 -19
  398. package/src/utils/storage/types.ts +15 -8
  399. package/src/utils/validation/__tests__/csrf.test.ts +105 -0
  400. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +92 -0
  401. package/src/vite-env.d.ts +2 -2
  402. package/dist/chunk-3GOZZZYH.js.map +0 -1
  403. package/dist/chunk-DDM4CCYT.js.map +0 -1
  404. package/dist/chunk-E7UAOUMY.js +0 -75
  405. package/dist/chunk-E7UAOUMY.js.map +0 -1
  406. package/dist/chunk-EFCLXK7F.js.map +0 -1
  407. package/dist/chunk-F2IMUDXZ.js.map +0 -1
  408. package/dist/chunk-HEHYGYOX.js.map +0 -1
  409. package/dist/chunk-IM4QE42D.js.map +0 -1
  410. package/dist/chunk-IPCH26AG.js.map +0 -1
  411. package/dist/chunk-SAUPYVLF.js.map +0 -1
  412. package/dist/chunk-THRPYOFK.js.map +0 -1
  413. package/dist/chunk-UNOTYLQF.js.map +0 -1
  414. package/dist/chunk-VGZZXKBR.js.map +0 -1
  415. package/dist/chunk-YHCN776L.js.map +0 -1
  416. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +0 -192
  417. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +0 -741
  418. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -703
  419. package/src/rbac/hooks/useRBAC.simple.test.ts +0 -95
  420. package/src/rbac/utils/__tests__/eventContext.unit.test.ts +0 -428
  421. /package/dist/{DataTable-GUFUNZ3N.js.map → DataTable-ON3IXISJ.js.map} +0 -0
  422. /package/dist/{UnifiedAuthProvider-643PUAIM.js.map → UnifiedAuthProvider-X5NXANVI.js.map} +0 -0
  423. /package/dist/{api-YP7XD5L6.js.map → api-I6UCQ5S6.js.map} +0 -0
  424. /package/dist/{chunk-HESYZWZW.js.map → chunk-QWWZ5CAQ.js.map} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/services/UnifiedAuthProvider.tsx","../src/providers/services/AuthServiceProvider.tsx","../src/services/AuthService.ts","../src/services/base/BaseService.ts","../src/providers/services/OrganisationServiceProvider.tsx","../src/services/OrganisationService.ts","../src/providers/services/EventServiceProvider.tsx","../src/services/EventService.ts","../src/providers/services/InactivityServiceProvider.tsx","../src/services/InactivityService.ts","../src/hooks/services/useAuthService.ts","../src/hooks/services/useOrganisationService.ts","../src/hooks/services/useEventService.ts","../src/hooks/services/useInactivityService.ts","../src/hooks/useSessionRestoration.ts"],"sourcesContent":["/**\n * @file Unified Auth Provider\n * @package @jmruthers/pace-core\n * @module Providers/Services\n * @since 0.1.0\n *\n * Unified authentication provider for authentication, organisations, events, and inactivity tracking.\n * Note: RBAC functionality is available via useRBAC() hook from '@jmruthers/pace-core/rbac'\n */\n\nimport React, { createContext, useContext, useMemo, useCallback, useRef, useEffect, useState, useReducer } from 'react';\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { AuthServiceProvider } from './AuthServiceProvider';\nimport { OrganisationServiceProvider } from './OrganisationServiceProvider';\nimport { EventServiceProvider } from './EventServiceProvider';\nimport { InactivityServiceProvider } from './InactivityServiceProvider';\nimport { useAuthService } from '../../hooks/services/useAuthService';\nimport { useOrganisationService } from '../../hooks/services/useOrganisationService';\nimport { useEventService } from '../../hooks/services/useEventService';\nimport { useInactivityService } from '../../hooks/services/useInactivityService';\nimport { useSessionRestoration } from '../../hooks/useSessionRestoration';\nimport type { Organisation, OrganisationMembership } from '../../types/organisation';\nimport type { Event } from '../../types/event';\nimport type { AuthError } from '@supabase/supabase-js';\nimport type { SessionRestorationState } from '../../types/auth';\nimport { logger } from '../../utils/core/logger';\n\n// Re-export UserEventAccess type\nexport interface UserEventAccess {\n event_id: string;\n event_name: string;\n event_description?: string | null;\n start_date: string;\n end_date: string;\n event_status: string;\n app_id: string;\n access_level: string;\n granted_at: string;\n organisation_id: string;\n}\n\n// Combined context type - focuses on auth, organisations, events, and inactivity\nexport interface UnifiedAuthContextType {\n // Auth state\n user: User | null;\n session: Session | null;\n isAuthenticated: boolean;\n authLoading: boolean;\n authError: AuthError | null;\n supabase: SupabaseClient | null;\n \n // App context (resolved immediately on login)\n appName: string;\n appId: string | undefined; // Resolved from appName when user logs in\n \n // Auth methods\n signIn: (email: string, password?: string) => Promise<{ error: AuthError | null }>;\n signUp: (email: string, password: string) => Promise<{ error: AuthError | null }>;\n signOut: () => Promise<{ error: AuthError | null }>;\n resetPassword: (email: string) => Promise<{ error: AuthError | null }>;\n updatePassword: (password: string) => Promise<{ error: AuthError | null }>;\n refreshSession: () => Promise<{ error: AuthError | null }>;\n\n // Organisation state\n selectedOrganisation: Organisation | null;\n organisations: Organisation[];\n userMemberships: OrganisationMembership[];\n organisationLoading: boolean;\n organisationError: Error | null;\n hasValidOrganisationContext: boolean;\n isContextReady: boolean;\n \n // Organisation methods\n switchOrganisation: (orgId: string) => Promise<void>;\n getUserRole: (orgId?: string) => string;\n validateOrganisationAccess: (orgId: string) => boolean;\n refreshOrganisations: () => Promise<void>;\n ensureOrganisationContext: () => Organisation;\n isOrganisationSecure: () => boolean;\n getPrimaryOrganisation: () => Organisation | null;\n\n // Event state\n events: Event[];\n selectedEvent: Event | null;\n eventLoading: boolean;\n eventError: Error | null;\n \n // Event methods\n setSelectedEvent: (event: Event | null) => void;\n refreshEvents: () => Promise<void>;\n\n // Inactivity state\n showInactivityWarning: boolean;\n inactivityTimeRemaining: number;\n isIdle: boolean;\n timeRemaining: number;\n showWarning: boolean;\n isTracking: boolean;\n \n // Inactivity methods\n resetActivity: () => void;\n startTracking: () => void;\n stopTracking: () => void;\n handleIdleLogout: () => Promise<void>;\n handleStaySignedIn: () => void;\n handleSignOutNow: () => Promise<void>;\n\n // Additional unified properties\n appConfig: { requires_event: boolean } | null;\n isLoading: boolean;\n hasErrors: boolean;\n sessionRestoration: SessionRestorationState;\n sessionRestorationTimedOut: boolean;\n sessionRestorationTimeoutMs: number;\n}\n\nexport const UnifiedAuthContext = createContext<UnifiedAuthContextType | undefined>(undefined);\n\nexport const useUnifiedAuth = () => {\n const context = useContext(UnifiedAuthContext);\n if (!context) {\n // Provide a helpful error log in addition to throwing for testability and DX\n logger.error('useUnifiedAuth', 'useUnifiedAuth must be used within a UnifiedAuthProvider');\n throw new Error('useUnifiedAuth must be used within a UnifiedAuthProvider');\n }\n return context;\n};\n\nexport interface UnifiedAuthProviderProps {\n children: React.ReactNode;\n supabaseClient: SupabaseClient;\n appName: string;\n persistState?: boolean;\n enablePersistence?: boolean;\n requireOrganisationContext?: boolean;\n \n // App configuration\n appConfig?: { requires_event: boolean } | null;\n \n // Inactivity auto-logout configuration - MANDATORY for security\n idleTimeoutMs: number; // REQUIRED: Inactivity timeout in milliseconds\n warnBeforeMs: number; // REQUIRED: Warning time before logout in milliseconds\n onIdleLogout: (reason: 'inactivity') => void; // REQUIRED: App handles redirect/navigation\n renderInactivityWarning?: (args: {\n timeRemaining: number;\n onStaySignedIn: () => void;\n onSignOutNow: () => void;\n }) => React.ReactNode; // Optional custom warning UI\n dangerouslyDisableInactivity?: boolean; // Dev-only; must not disable in production\n}\n\n// Internal component that combines all contexts\nfunction UnifiedAuthContextProvider({ \n children, \n appName,\n appConfig = { requires_event: true }, // Default to requiring events\n ...props \n}: UnifiedAuthProviderProps) {\n const authService = useAuthService();\n const organisationService = useOrganisationService();\n const inactivityService = useInactivityService();\n const sessionRestorationState = useSessionRestoration();\n const {\n hasTimedOut: sessionRestorationTimedOut,\n timeoutMs: sessionRestorationTimeoutMs,\n isRestoring,\n restorationComplete,\n restorationError,\n } = sessionRestorationState;\n const sessionRestoration: SessionRestorationState = useMemo(() => ({\n isRestoring,\n restorationComplete,\n restorationError,\n }), [isRestoring, restorationComplete, restorationError]);\n\n // Try to get event service, but provide fallback if not available\n let eventService;\n try {\n eventService = useEventService();\n } catch (error) {\n // EventService not available - provide fallback implementation\n // Include subscribe method to match BaseService interface\n eventService = {\n getEvents: () => [],\n getSelectedEvent: () => null,\n isLoading: () => false,\n getError: () => null,\n setSelectedEvent: () => {},\n refreshEvents: async () => {},\n subscribe: () => () => {} // No-op subscribe/unsubscribe for fallback\n };\n }\n\n // Get current auth state - these will trigger re-renders when services change\n const currentUser = authService.getUser();\n const currentSession = authService.getSession();\n const isAuth = !!(currentUser && currentSession);\n \n // Get supabase client early so we can use it in useEffect\n const supabase = authService.getSupabaseClient();\n \n // Resolve appId immediately when user logs in (don't wait for organisation/event)\n // This makes appId available early for navigation menu filtering\n const [appId, setAppId] = useState<string | undefined>(undefined);\n const isResolvingAppIdRef = useRef(false);\n \n useEffect(() => {\n // Resolve appId as soon as we have user + supabase + appName\n // Don't wait for organisation or event - appId resolution only needs user + appName\n if (\n isAuth &&\n currentUser?.id &&\n supabase &&\n appName &&\n !appId &&\n !isResolvingAppIdRef.current\n ) {\n isResolvingAppIdRef.current = true;\n const userId = currentUser.id;\n const appNameValue = appName;\n \n // Resolve appId immediately\n import('../../rbac/api').then(async ({ resolveAppContext, setupRBAC }) => {\n try {\n // Ensure RBAC is initialized (idempotent - safe to call multiple times)\n setupRBAC(supabase);\n \n const result = await resolveAppContext({\n userId,\n appName: appNameValue\n });\n \n if (result?.appId) {\n setAppId(result.appId);\n logger.debug('UnifiedAuthProvider', 'appId resolved on login', {\n appId: result.appId,\n appName: appNameValue\n });\n }\n } catch (error) {\n logger.error('UnifiedAuthProvider', 'Failed to resolve appId on login', {\n error: error instanceof Error ? error.message : String(error),\n appName: appNameValue,\n userId\n });\n } finally {\n isResolvingAppIdRef.current = false;\n }\n }).catch((importError) => {\n logger.error('UnifiedAuthProvider', 'Failed to import RBAC API', importError);\n isResolvingAppIdRef.current = false;\n });\n }\n \n // Clear appId when user logs out\n if (!isAuth) {\n setAppId(undefined);\n }\n }, [isAuth, currentUser?.id, supabase, appName, appId]);\n\n // Subscribe to service state changes to trigger re-renders\n // Use useReducer to force updates when services notify\n const [, forceUpdate] = useReducer(x => x + 1, 0);\n \n useEffect(() => {\n // Subscribe to all service changes\n const unsubscribeAuth = authService.subscribe(() => forceUpdate());\n const unsubscribeOrg = organisationService.subscribe(() => forceUpdate());\n const unsubscribeEvent = eventService.subscribe(() => forceUpdate());\n const unsubscribeInactivity = inactivityService.subscribe(() => forceUpdate());\n \n return () => {\n unsubscribeAuth();\n unsubscribeOrg();\n unsubscribeEvent();\n unsubscribeInactivity();\n };\n }, [authService, organisationService, eventService, inactivityService]);\n\n // Get loading states - these will trigger re-renders when services change\n const authLoading = authService.isLoading();\n const orgLoading = organisationService.isLoading();\n const eventLoading = eventService.isLoading();\n const restorationLoading = sessionRestoration.isRestoring && !sessionRestorationTimedOut && !sessionRestoration.restorationError;\n const totalLoading = restorationLoading || authLoading || orgLoading || eventLoading;\n \n // Extract all primitive values from services to use in dependencies\n const authError = authService.getError();\n // supabase is already declared above (line 198)\n const selectedOrganisation = organisationService.getSelectedOrganisation();\n const organisations = organisationService.getOrganisations();\n const userMemberships = organisationService.getUserMemberships();\n const organisationError = organisationService.getError();\n const hasValidOrganisationContext = organisationService.hasValidOrganisationContext();\n const isContextReady = organisationService.isContextReady();\n const events = eventService.getEvents();\n const selectedEvent = eventService.getSelectedEvent();\n const eventError = eventService.getError();\n const showInactivityWarning = inactivityService.getShowInactivityWarning();\n const inactivityTimeRemaining = inactivityService.getInactivityTimeRemaining();\n const isIdle = inactivityService.isIdle();\n const timeRemaining = inactivityService.getTimeRemaining();\n const showWarning = inactivityService.isWarningShown();\n const isTracking = inactivityService.isTracking();\n const hasErrors = !!(authError || organisationError || eventError || sessionRestoration.restorationError);\n\n // Create stable references for all methods using useCallback\n const signIn = useCallback((email: string, password?: string) => authService.signIn(email, password), [authService]);\n const signUp = useCallback((email: string, password: string) => authService.signUp(email, password), [authService]);\n const signOut = useCallback(() => authService.signOut(), [authService]);\n const resetPassword = useCallback((email: string) => authService.resetPassword(email), [authService]);\n const updatePassword = useCallback((password: string) => authService.updatePassword(password), [authService]);\n const refreshSession = useCallback(() => authService.refreshSession(), [authService]);\n \n const switchOrganisation = useCallback((orgId: string) => organisationService.switchOrganisation(orgId), [organisationService]);\n const getUserRole = useCallback((orgId?: string) => organisationService.getUserRole(orgId), [organisationService]);\n const validateOrganisationAccess = useCallback((orgId: string) => organisationService.validateOrganisationAccess(orgId), [organisationService]);\n const refreshOrganisations = useCallback(() => organisationService.refreshOrganisations(), [organisationService]);\n const ensureOrganisationContext = useCallback(() => organisationService.ensureOrganisationContext(), [organisationService]);\n const isOrganisationSecure = useCallback(() => organisationService.isOrganisationSecure(), [organisationService]);\n const getPrimaryOrganisation = useCallback(() => organisationService.getPrimaryOrganisation(), [organisationService]);\n \n const setSelectedEvent = useCallback((event: Event | null) => eventService.setSelectedEvent(event), [eventService]);\n const refreshEvents = useCallback(() => eventService.refreshEvents(), [eventService]);\n \n const resetActivity = useCallback(() => inactivityService.resetActivity(), [inactivityService]);\n const startTracking = useCallback(() => inactivityService.startTracking(), [inactivityService]);\n const stopTracking = useCallback(() => inactivityService.stopTracking(), [inactivityService]);\n const handleIdleLogout = useCallback(() => inactivityService.handleIdleLogout(), [inactivityService]);\n const handleStaySignedIn = useCallback(() => inactivityService.handleStaySignedIn(), [inactivityService]);\n const handleSignOutNow = useCallback(() => inactivityService.handleSignOutNow(), [inactivityService]);\n\n // Use ref to track previous state for conditional logging (dev only)\n const prevStateRef = useRef<{\n isAuthenticated: boolean;\n userEmail: string | undefined;\n totalLoading: boolean;\n } | null>(null);\n \n // Only log when state actually changes (dev mode detection)\n const isDev = import.meta.env.DEV || import.meta.env.MODE === 'development';\n if (isDev) {\n const currentState = {\n isAuthenticated: isAuth,\n userEmail: currentUser?.email,\n totalLoading,\n };\n \n const prevState = prevStateRef.current;\n if (!prevState || \n prevState.isAuthenticated !== currentState.isAuthenticated ||\n prevState.userEmail !== currentState.userEmail ||\n prevState.totalLoading !== currentState.totalLoading) {\n // State change detected, notify subscribers\n prevStateRef.current = currentState;\n }\n }\n \n // Memoized combined context value - only depends on primitive values\n const contextValue = useMemo<UnifiedAuthContextType>(() => {\n return {\n // Auth state\n user: currentUser,\n session: currentSession,\n isAuthenticated: isAuth,\n authLoading: authLoading,\n authError: authError,\n supabase: supabase,\n \n // Auth methods\n signIn,\n signUp,\n signOut,\n resetPassword,\n updatePassword,\n refreshSession,\n\n // Organisation state\n selectedOrganisation: selectedOrganisation,\n organisations: organisations,\n userMemberships: userMemberships,\n organisationLoading: orgLoading,\n organisationError: organisationError,\n hasValidOrganisationContext: hasValidOrganisationContext,\n isContextReady: isContextReady,\n \n // Organisation methods\n switchOrganisation,\n getUserRole,\n validateOrganisationAccess,\n refreshOrganisations,\n ensureOrganisationContext,\n isOrganisationSecure,\n getPrimaryOrganisation,\n\n // Event state\n events: events,\n selectedEvent: selectedEvent,\n eventLoading: eventLoading,\n eventError: eventError,\n \n // Event methods\n setSelectedEvent,\n refreshEvents,\n\n // Inactivity state\n showInactivityWarning: showInactivityWarning,\n inactivityTimeRemaining: inactivityTimeRemaining,\n isIdle: isIdle,\n timeRemaining: timeRemaining,\n showWarning: showWarning,\n isTracking: isTracking,\n \n // Inactivity methods\n resetActivity,\n startTracking,\n stopTracking,\n handleIdleLogout,\n handleStaySignedIn,\n handleSignOutNow,\n\n // Additional unified properties\n appName,\n appId, // Resolved immediately on login\n appConfig: appConfig,\n isLoading: totalLoading,\n hasErrors: hasErrors,\n sessionRestoration: sessionRestoration,\n sessionRestorationTimedOut,\n sessionRestorationTimeoutMs,\n };\n }, [\n // All primitive values extracted from services\n // Note: Arrays/objects from services are stable references (same reference unless data changes)\n currentUser,\n currentSession,\n isAuth,\n authLoading,\n authError,\n supabase,\n selectedOrganisation,\n organisations,\n userMemberships,\n orgLoading,\n organisationError,\n hasValidOrganisationContext,\n isContextReady,\n events,\n selectedEvent,\n eventLoading,\n eventError,\n showInactivityWarning,\n inactivityTimeRemaining,\n isIdle,\n timeRemaining,\n showWarning,\n isTracking,\n totalLoading,\n hasErrors,\n appName,\n appId,\n appConfig,\n sessionRestoration,\n sessionRestorationTimedOut,\n sessionRestorationTimeoutMs,\n // Stable function references from useCallback (services are stable, so callbacks are too)\n signIn,\n signUp,\n signOut,\n resetPassword,\n updatePassword,\n refreshSession,\n switchOrganisation,\n getUserRole,\n validateOrganisationAccess,\n refreshOrganisations,\n ensureOrganisationContext,\n isOrganisationSecure,\n getPrimaryOrganisation,\n setSelectedEvent,\n refreshEvents,\n resetActivity,\n startTracking,\n stopTracking,\n handleIdleLogout,\n handleStaySignedIn,\n handleSignOutNow,\n ]);\n\n return (\n <UnifiedAuthContext.Provider value={contextValue}>\n {children}\n </UnifiedAuthContext.Provider>\n );\n}\n\n// Wrapper for EventServiceProvider that reads selectedOrganisation from OrganisationService\nfunction EventServiceProviderWrapper({ \n children, \n supabaseClient,\n user,\n session,\n appName\n}: {\n children: React.ReactNode;\n supabaseClient: SupabaseClient;\n user: User | null;\n session: Session | null;\n appName: string;\n}) {\n const organisationService = useOrganisationService();\n const selectedOrganisation = organisationService.getSelectedOrganisation();\n\n // Always render EventServiceProvider - it handles null user/session gracefully\n // This ensures EventServiceContext is always available for components calling useEvents()\n return (\n <EventServiceProvider\n supabaseClient={supabaseClient}\n user={user}\n session={session}\n appName={appName}\n selectedOrganisation={selectedOrganisation}\n setSelectedEventId={() => {\n // Event selection is now handled at the application level\n }}\n >\n {children}\n </EventServiceProvider>\n );\n}\n\n// Internal component that provides user/session to child providers\nfunction ServiceAwareProviders({ \n children, \n supabaseClient,\n appName,\n appConfig,\n persistState,\n enablePersistence,\n requireOrganisationContext,\n idleTimeoutMs,\n warnBeforeMs,\n onIdleLogout,\n renderInactivityWarning,\n dangerouslyDisableInactivity\n}: UnifiedAuthProviderProps) {\n const authService = useAuthService();\n\n return (\n <OrganisationServiceProvider\n supabaseClient={supabaseClient}\n user={authService.getUser()}\n session={authService.getSession()}\n >\n <EventServiceProviderWrapper\n supabaseClient={supabaseClient}\n user={authService.getUser()}\n session={authService.getSession()}\n appName={appName}\n >\n <InactivityServiceProvider\n supabaseClient={supabaseClient}\n user={authService.getUser()}\n session={authService.getSession()}\n idleTimeoutMs={idleTimeoutMs}\n warnBeforeMs={warnBeforeMs}\n onIdleLogout={onIdleLogout}\n >\n <UnifiedAuthContextProvider\n appName={appName}\n appConfig={appConfig}\n supabaseClient={supabaseClient}\n persistState={persistState}\n enablePersistence={enablePersistence}\n requireOrganisationContext={requireOrganisationContext}\n idleTimeoutMs={idleTimeoutMs}\n warnBeforeMs={warnBeforeMs}\n onIdleLogout={onIdleLogout}\n renderInactivityWarning={renderInactivityWarning}\n dangerouslyDisableInactivity={dangerouslyDisableInactivity}\n >\n {children}\n </UnifiedAuthContextProvider>\n </InactivityServiceProvider>\n </EventServiceProviderWrapper>\n </OrganisationServiceProvider>\n );\n}\n\nexport function UnifiedAuthProvider({\n children,\n supabaseClient,\n appName,\n appConfig = { requires_event: true }, // Default to requiring events\n persistState = true,\n enablePersistence,\n requireOrganisationContext = true,\n idleTimeoutMs = 30 * 60 * 1000, // 30 minutes\n warnBeforeMs = 60 * 1000, // 60 seconds\n onIdleLogout,\n renderInactivityWarning,\n dangerouslyDisableInactivity = false\n}: UnifiedAuthProviderProps) {\n // Warn if supabaseClient reference changes (indicates multiple client instances)\n const clientRef = useRef(supabaseClient);\n useEffect(() => {\n if (clientRef.current !== supabaseClient) {\n logger.warn('UnifiedAuthProvider', 'Supabase client reference changed - this may indicate multiple client instances are being created', {\n previousClient: clientRef.current,\n newClient: supabaseClient,\n note: 'Ensure you create the Supabase client once and reuse it. Creating multiple clients can cause performance issues and the \"Multiple GoTrueClient instances\" warning.'\n });\n clientRef.current = supabaseClient;\n }\n }, [supabaseClient]);\n\n return (\n <AuthServiceProvider supabaseClient={supabaseClient} appName={appName}>\n <ServiceAwareProviders\n supabaseClient={supabaseClient}\n appName={appName}\n appConfig={appConfig}\n persistState={persistState}\n enablePersistence={enablePersistence}\n requireOrganisationContext={requireOrganisationContext}\n idleTimeoutMs={idleTimeoutMs}\n warnBeforeMs={warnBeforeMs}\n onIdleLogout={onIdleLogout}\n renderInactivityWarning={renderInactivityWarning}\n dangerouslyDisableInactivity={dangerouslyDisableInactivity}\n >\n {children}\n </ServiceAwareProviders>\n </AuthServiceProvider>\n );\n}\n","/**\n * @file Auth Service Provider\n * @package @jmruthers/pace-core\n * @module Providers/Services\n * @since 0.1.0\n *\n * React provider for AuthService.\n * Provides authentication service instance to React components.\n */\n\nimport React, { createContext, useMemo, useEffect, useState } from 'react';\nimport { type SupabaseClient } from '@supabase/supabase-js';\nimport { AuthService } from '../../services/AuthService';\nimport type { SessionRestorationState } from '../../types/auth';\nimport { logger } from '../../utils/core/logger';\n\n// Context type\nexport interface AuthServiceContextType {\n authService: AuthService;\n sessionRestoration: SessionRestorationState;\n}\n\nexport const AuthServiceContext = createContext<AuthServiceContextType | null>(null);\n\nexport interface AuthServiceProviderProps {\n children: React.ReactNode;\n supabaseClient: SupabaseClient;\n appName?: string;\n}\n\nexport function AuthServiceProvider({ children, supabaseClient, appName }: AuthServiceProviderProps) {\n // Create service instance with useMemo to prevent recreation on every render\n const authService = useMemo(\n () => new AuthService(supabaseClient, appName),\n [supabaseClient, appName]\n );\n\n const [sessionRestoration, setSessionRestoration] = useState<SessionRestorationState>(\n () => authService.getSessionRestorationState()\n );\n\n // Subscribe to service updates to keep restoration state in sync\n useEffect(() => {\n const unsubscribe = authService.subscribe(() => {\n const restorationState = authService.getSessionRestorationState();\n setSessionRestoration(restorationState);\n });\n\n return () => {\n unsubscribe();\n };\n }, [authService]);\n\n // Initialize service on mount\n useEffect(() => {\n authService.initialize().catch(error => {\n logger.error('AuthServiceProvider', 'Failed to initialize auth service:', error);\n });\n\n // Cleanup on unmount\n return () => {\n authService.cleanup();\n };\n }, [authService]);\n\n const contextValue = useMemo(() => ({\n authService,\n sessionRestoration\n }), [authService, sessionRestoration]);\n\n return (\n <AuthServiceContext.Provider value={contextValue}>\n {children}\n </AuthServiceContext.Provider>\n );\n}","/**\n * @file Authentication Service\n * @package @jmruthers/pace-core\n * @module Services\n * @since 0.1.0\n *\n * Authentication service implementation.\n * Handles user authentication, session management, and auth-related operations.\n */\n\nimport { type SupabaseClient, type User, type Session, AuthError, type AuthChangeEvent, type Session as SupabaseSession } from '@supabase/supabase-js';\nimport type { SessionRestorationState } from '../types/auth';\nimport { BaseService } from './base/BaseService';\nimport { IAuthService, AuthResult } from './interfaces/IAuthService';\nimport { logger } from '../utils/core/logger';\n\ntype AuthStateSubscription = {\n data: {\n subscription: {\n unsubscribe: () => void;\n };\n };\n};\n\nexport class AuthService extends BaseService implements IAuthService {\n private user: User | null = null;\n private session: Session | null = null;\n private authLoading = false;\n private authError: AuthError | null = null;\n private supabaseClient: SupabaseClient | null = null;\n private authStateSubscription: { unsubscribe: () => void } | null = null;\n private sessionRestorationState: SessionRestorationState = {\n isRestoring: false,\n restorationComplete: false,\n restorationError: null,\n };\n private restorationTimeoutId: ReturnType<typeof setTimeout> | null = null;\n private readonly restorationTimeoutMs = 5000;\n private restorationStartTime: number | null = null;\n private appName: string | undefined = undefined;\n private errorHandler: ((event: ErrorEvent) => void) | null = null;\n private unhandledRejectionHandler: ((event: PromiseRejectionEvent) => void) | null = null;\n\n constructor(supabaseClient: SupabaseClient, appName?: string) {\n super();\n this.supabaseClient = supabaseClient;\n this.appName = appName;\n }\n\n // Auth state getters\n getUser(): User | null {\n return this.user;\n }\n\n getSession(): Session | null {\n return this.session;\n }\n\n isAuthenticated(): boolean {\n return !!(this.user && this.session);\n }\n\n isLoading(): boolean {\n return this.authLoading;\n }\n\n getError(): AuthError | null {\n return this.authError;\n }\n\n getSupabaseClient(): SupabaseClient | null {\n return this.supabaseClient;\n }\n\n getSessionRestorationState(): SessionRestorationState {\n return { ...this.sessionRestorationState };\n }\n\n // Auth methods\n async signIn(email: string, password?: string): Promise<AuthResult> {\n if (!this.supabaseClient) {\n const error = new AuthError('Supabase client not available');\n this.authError = error;\n this.notify();\n return { user: null, session: null, error };\n }\n\n try {\n const { data, error } = await this.supabaseClient.auth.signInWithPassword({\n email,\n password: password || '',\n });\n \n if (error) {\n this.authError = error;\n this.user = null;\n this.session = null;\n } else {\n this.authError = null;\n this.user = data.user;\n this.session = data.session;\n }\n \n this.notify();\n return { user: data.user, session: data.session, error };\n } catch (error) {\n // Convert regular Error to AuthError if needed\n const authError = error instanceof AuthError \n ? error \n : new AuthError(error instanceof Error ? error.message : 'Authentication failed');\n this.authError = authError;\n this.user = null;\n this.session = null;\n this.notify();\n return { user: null, session: null, error: authError };\n }\n }\n\n async signUp(email: string, password: string): Promise<AuthResult> {\n if (!this.supabaseClient) {\n const error = new AuthError('Supabase client not available');\n this.authError = error;\n this.notify();\n return { user: null, session: null, error };\n }\n\n try {\n const { data, error } = await this.supabaseClient.auth.signUp({\n email,\n password,\n });\n \n if (error) {\n this.authError = error;\n this.user = null;\n this.session = null;\n } else {\n this.authError = null;\n this.user = data.user;\n this.session = data.session;\n }\n \n this.notify();\n return { user: data.user, session: data.session, error };\n } catch (error) {\n // Convert regular Error to AuthError if needed\n const authError = error instanceof AuthError \n ? error \n : new AuthError(error instanceof Error ? error.message : 'Authentication failed');\n this.authError = authError;\n this.user = null;\n this.session = null;\n this.notify();\n return { user: null, session: null, error: authError };\n }\n }\n\n async signOut(): Promise<AuthResult> {\n if (!this.supabaseClient) {\n const error = new AuthError('Supabase client not available');\n this.authError = error;\n this.notify();\n return { user: null, session: null, error };\n }\n\n try {\n const { error } = await this.supabaseClient.auth.signOut();\n \n if (error) {\n this.authError = error;\n } else {\n this.authError = null;\n this.user = null;\n this.session = null;\n }\n \n this.notify();\n return { user: null, session: null, error };\n } catch (error) {\n // Convert regular Error to AuthError if needed\n const authError = error instanceof AuthError \n ? error \n : new AuthError(error instanceof Error ? error.message : 'Authentication failed');\n this.authError = authError;\n this.user = null;\n this.session = null;\n this.notify();\n return { user: null, session: null, error: authError };\n }\n }\n\n async resetPassword(email: string): Promise<AuthResult> {\n if (!this.supabaseClient) {\n const error = new AuthError('Supabase client not available');\n this.authError = error;\n this.notify();\n return { user: null, session: null, error };\n }\n\n try {\n const { error } = await this.supabaseClient.auth.resetPasswordForEmail(email);\n \n if (error) {\n this.authError = error;\n } else {\n this.authError = null;\n }\n \n this.notify();\n return { user: null, session: null, error };\n } catch (error) {\n // Convert regular Error to AuthError if needed\n const authError = error instanceof AuthError \n ? error \n : new AuthError(error instanceof Error ? error.message : 'Authentication failed');\n this.authError = authError;\n this.notify();\n return { user: null, session: null, error: authError };\n }\n }\n\n async updatePassword(password: string): Promise<AuthResult> {\n if (!this.supabaseClient) {\n const error = new AuthError('Supabase client not available');\n this.authError = error;\n this.notify();\n return { user: null, session: null, error };\n }\n\n try {\n const { error } = await this.supabaseClient.auth.updateUser({\n password,\n });\n \n if (error) {\n this.authError = error;\n } else {\n this.authError = null;\n }\n \n this.notify();\n return { user: null, session: null, error };\n } catch (error) {\n const authError = error as AuthError;\n this.authError = authError;\n this.notify();\n return { user: null, session: null, error: authError };\n }\n }\n\n async refreshSession(): Promise<AuthResult> {\n if (!this.supabaseClient) {\n const error = new AuthError('Supabase client not available');\n this.authError = error;\n this.notify();\n return { user: null, session: null, error };\n }\n\n try {\n const { data, error } = await this.supabaseClient.auth.refreshSession();\n \n if (error) {\n this.authError = error;\n this.user = null;\n this.session = null;\n } else {\n this.authError = null;\n // Only update user and session if both are present (valid session)\n if (data?.user && data?.session) {\n this.user = data.user;\n this.session = data.session;\n } else {\n // If no valid session, clear everything\n this.user = null;\n this.session = null;\n }\n }\n \n this.notify();\n // Only return user if we have a valid session\n return { \n user: (data?.user && data?.session) ? data.user : null, \n session: data?.session ?? null, \n error \n };\n } catch (error) {\n // Convert regular Error to AuthError if needed\n const authError = error instanceof AuthError \n ? error \n : new AuthError(error instanceof Error ? error.message : 'Authentication failed');\n this.authError = authError;\n this.user = null;\n this.session = null;\n this.notify();\n return { user: null, session: null, error: authError };\n }\n }\n\n // Lifecycle methods\n async initialize(): Promise<void> {\n await super.initialize();\n await this.setupAuthStateListener();\n await this.restoreSession();\n }\n\n cleanup(): void {\n if (this.authStateSubscription) {\n this.authStateSubscription.unsubscribe();\n this.authStateSubscription = null;\n }\n this.clearRestorationTimeout();\n this.restorationStartTime = null;\n this.sessionRestorationState = {\n isRestoring: false,\n restorationComplete: false,\n restorationError: null,\n };\n this.authLoading = false;\n super.cleanup();\n }\n\n protected async doInitialize(): Promise<void> {\n // Setup global error handlers\n this.setupErrorHandlers();\n }\n\n protected doCleanup(): void {\n // Remove global error handlers\n this.removeErrorHandlers();\n }\n\n private startSessionRestoration(): void {\n this.clearRestorationTimeout();\n this.sessionRestorationState = {\n isRestoring: true,\n restorationComplete: false,\n restorationError: null,\n };\n this.authLoading = true;\n this.restorationStartTime = Date.now();\n this.notify();\n\n this.restorationTimeoutId = setTimeout(() => {\n logger.warn('AuthService', 'Session restoration timed out after', this.restorationTimeoutMs, 'ms');\n const timeoutError = new Error(`Session restoration timed out after ${this.restorationTimeoutMs}ms`);\n timeoutError.name = 'SessionRestorationTimeoutError';\n this.finishSessionRestoration(timeoutError);\n }, this.restorationTimeoutMs);\n }\n\n private finishSessionRestoration(error?: Error): void {\n if (!this.sessionRestorationState.isRestoring && !error) {\n return;\n }\n\n this.clearRestorationTimeout();\n const completedAt = Date.now();\n const duration = this.restorationStartTime ? completedAt - this.restorationStartTime : null;\n this.restorationStartTime = null;\n const restorationComplete = !error;\n this.sessionRestorationState = {\n isRestoring: false,\n restorationComplete,\n restorationError: error ?? null,\n };\n this.authLoading = false;\n\n if (error) {\n logger.warn('AuthService', 'Session restoration finished with error:', error);\n }\n\n this.notify();\n }\n\n private clearRestorationTimeout(): void {\n if (this.restorationTimeoutId) {\n clearTimeout(this.restorationTimeoutId);\n this.restorationTimeoutId = null;\n }\n }\n\n private async setupAuthStateListener(): Promise<void> {\n if (!this.supabaseClient) {\n this.authLoading = false;\n this.notify();\n return;\n }\n\n try {\n const subscription = this.supabaseClient.auth.onAuthStateChange(\n (event: AuthChangeEvent, session: SupabaseSession | null) => {\n try {\n // Handle different auth events\n if (event === 'SIGNED_OUT') {\n this.session = null;\n this.user = null;\n this.authError = null;\n \n // Automatic session tracking (non-blocking)\n if (session?.user) {\n this.trackSession('logout', session).catch(err => {\n logger.warn('AuthService', 'Failed to track logout session:', err);\n });\n }\n } else if (event === 'SIGNED_IN' || event === 'TOKEN_REFRESHED') {\n this.session = session;\n this.user = session?.user ?? null;\n\n // Only clear auth error if we have a valid session\n if (session) {\n this.authError = null;\n }\n \n // Automatic session tracking for login (non-blocking)\n // Only track on SIGNED_IN, not TOKEN_REFRESHED (to avoid duplicate login records)\n if (event === 'SIGNED_IN' && session?.user) {\n this.trackSession('login', session).catch(err => {\n logger.warn('AuthService', 'Failed to track login session:', err);\n });\n }\n } else if (event === 'INITIAL_SESSION') {\n if (session) {\n this.session = session;\n this.user = session.user ?? null;\n this.authError = null;\n \n // Reset restoration state if valid session arrives after earlier failure\n // This clears stale errors when session eventually succeeds\n const hasTimeoutError = this.sessionRestorationState.restorationError?.name === 'SessionRestorationTimeoutError';\n if (this.sessionRestorationState.isRestoring || \n this.sessionRestorationState.restorationError ||\n (hasTimeoutError && session)) {\n this.finishSessionRestoration();\n return;\n }\n }\n\n if (this.sessionRestorationState.isRestoring) {\n this.finishSessionRestoration();\n return;\n }\n }\n\n // Always set loading to false after any auth state change\n this.authLoading = false;\n this.notify();\n } catch (error) {\n logger.warn('AuthService', 'Error in auth state change handler:', error);\n this.authLoading = false;\n this.notify();\n }\n }\n );\n this.authStateSubscription = subscription.data.subscription;\n } catch (error) {\n logger.error('AuthService', 'Failed to setup auth state listener:', error);\n throw error; // Re-throw to propagate to the provider\n }\n }\n\n private async restoreSession(): Promise<void> {\n if (!this.supabaseClient) {\n const error = new Error('Supabase client not available during session restoration');\n logger.error('AuthService', 'Unable to restore session:', error);\n this.finishSessionRestoration(error);\n return;\n }\n\n this.startSessionRestoration();\n\n try {\n let currentSession: Session | null = null;\n let sessionError: AuthError | null = null;\n\n try {\n const { data, error } = await this.supabaseClient.auth.getSession();\n currentSession = data?.session ?? null;\n sessionError = error ?? null;\n } catch (error) {\n // Handle cases where getSession might not exist (mocked/test clients)\n currentSession = null;\n sessionError = null;\n }\n\n if (sessionError) {\n // Record error but continue to attempt getUser to satisfy edge cases\n this.authError = sessionError;\n \n // Attempt getUser as fallback when getSession fails\n try {\n const { data, error } = await this.supabaseClient.auth.getUser();\n const currentUser = data?.user ?? null;\n const userError = error ?? null;\n \n if (currentUser) {\n this.user = currentUser;\n // If we got a user but no session, we still don't have a valid session\n this.session = null;\n }\n if (userError && !this.authError) {\n this.authError = userError;\n }\n } catch (getUserError) {\n // If getUser also fails, we've already recorded the sessionError\n }\n }\n\n if (currentSession) {\n this.session = currentSession;\n this.user = currentSession.user;\n this.authError = null;\n } else if (!sessionError) {\n // Only skip getUser if we didn't already attempt it due to a sessionError\n // Treat missing session as a normal cold-start state on public pages (e.g., login)\n // Do not call getUser() which can raise AuthSessionMissingError and surface a noisy banner\n // No active session found; treating as normal unauthenticated state\n this.session = null;\n this.user = null;\n this.authError = null;\n }\n\n // Finish successfully even if earlier calls reported an error, to avoid noisy warnings in benign cases\n this.finishSessionRestoration();\n } catch (error) {\n const restorationError = error instanceof Error\n ? error\n : new Error('Unknown error during auth initialization');\n logger.error('AuthService', 'Error during auth initialization:', restorationError);\n if (restorationError instanceof AuthError) {\n this.authError = restorationError;\n }\n this.finishSessionRestoration(restorationError);\n }\n }\n\n /**\n * Automatically track user session using rbac_session_track\n * This method is called automatically on SIGNED_IN and SIGNED_OUT events.\n * It's non-blocking and failures are logged as warnings.\n */\n private async trackSession(\n sessionType: 'login' | 'logout',\n session: Session | null\n ): Promise<void> {\n if (!this.supabaseClient || !session?.user) {\n return;\n }\n\n try {\n // Resolve app_id from appName if available\n let appId: string | undefined = undefined;\n if (this.appName) {\n const { data, error } = await this.supabaseClient\n .from('rbac_apps')\n .select('id')\n .eq('name', this.appName)\n .eq('is_active', true)\n .single();\n \n if (!error && data) {\n appId = data.id;\n }\n }\n\n // Get IP address and user agent from browser (if available)\n const ipAddress = undefined; // Browser doesn't expose IP directly, could use API\n const userAgent = typeof navigator !== 'undefined' ? navigator.userAgent : undefined;\n \n // Get device fingerprint from localStorage if available\n // Note: Device fingerprinting should be done by consuming app and passed via custom header\n // For now, we'll skip it to avoid dependencies\n const deviceFingerprint = undefined;\n\n // Call rbac_session_track RPC function\n // This automatically inserts into rbac_user_sessions AND rbac_user_login_history (for login)\n // Note: Using type assertion for RPC call as Supabase doesn't provide full typing for custom RPC functions\n const { error } = await (this.supabaseClient as unknown as { rpc: (name: string, params: Record<string, unknown>) => Promise<{ error: Error | null }> }).rpc('rbac_session_track', {\n p_user_id: session.user.id,\n p_session_type: sessionType,\n p_event_id: null, // Event ID should come from context, not auth service\n p_app_id: appId,\n p_ip_address: ipAddress,\n p_user_agent: userAgent,\n p_device_fingerprint: deviceFingerprint,\n });\n\n if (error) {\n logger.warn('AuthService', `Failed to track ${sessionType} session:`, error);\n }\n } catch (error) {\n // Log error but don't throw (non-blocking)\n logger.warn('AuthService', `Error tracking ${sessionType} session:`, error);\n }\n }\n\n private setupErrorHandlers(): void {\n if (typeof window === 'undefined') return;\n\n this.errorHandler = (event: ErrorEvent) => {\n if (event.error?.message?.includes('AuthSessionMissingError') || \n event.error?.message?.includes('Auth session missing')) {\n logger.warn('AuthService', 'Suppressing AuthSessionMissingError during logout');\n event.preventDefault();\n return false;\n }\n };\n\n this.unhandledRejectionHandler = (event: PromiseRejectionEvent) => {\n if (event.reason?.message?.includes('AuthSessionMissingError') ||\n event.reason?.message?.includes('Auth session missing')) {\n logger.warn('AuthService', 'Suppressing unhandled AuthSessionMissingError');\n event.preventDefault();\n return false;\n }\n };\n\n window.addEventListener('error', this.errorHandler);\n window.addEventListener('unhandledrejection', this.unhandledRejectionHandler);\n }\n\n private removeErrorHandlers(): void {\n if (typeof window === 'undefined') return;\n\n if (this.errorHandler) {\n window.removeEventListener('error', this.errorHandler);\n this.errorHandler = null;\n }\n\n if (this.unhandledRejectionHandler) {\n window.removeEventListener('unhandledrejection', this.unhandledRejectionHandler);\n this.unhandledRejectionHandler = null;\n }\n }\n}","/**\n * @file Base Service Class\n * @package @jmruthers/pace-core\n * @module Services/Base\n * @since 0.1.0\n *\n * Base service class implementing the observable pattern for React subscriptions.\n * All services extend this class to provide state change notifications.\n */\n\nimport { logger } from '../../utils/core/logger';\n\nexport type StateChangeCallback = () => void;\n\nexport abstract class BaseService {\n private subscribers: Array<StateChangeCallback> = [];\n private isInitialized = false;\n\n /**\n * Subscribe to state changes\n * @param callback Function to call when state changes\n * @returns Unsubscribe function\n */\n subscribe(callback: StateChangeCallback): () => void {\n this.subscribers.push(callback);\n \n // Return unsubscribe function that removes only the first occurrence\n return () => {\n const index = this.subscribers.indexOf(callback);\n if (index > -1) {\n this.subscribers.splice(index, 1);\n }\n };\n }\n\n /**\n * Notify all subscribers of state changes\n * This triggers React re-renders\n */\n protected notify(): void {\n this.subscribers.forEach(callback => {\n try {\n callback();\n } catch (error) {\n logger.error('BaseService', 'Error in subscriber callback:', error);\n }\n });\n }\n\n /**\n * Initialize the service\n * Override in subclasses to implement initialization logic\n */\n async initialize(): Promise<void> {\n if (this.isInitialized) {\n return;\n }\n \n await this.doInitialize();\n this.isInitialized = true;\n }\n\n /**\n * Cleanup the service\n * Override in subclasses to implement cleanup logic\n */\n cleanup(): void {\n this.subscribers = [];\n this.doCleanup();\n this.isInitialized = false;\n }\n\n /**\n * Check if service is initialized\n */\n protected getInitialized(): boolean {\n return this.isInitialized;\n }\n\n /**\n * Reset initialization state (allows re-initialization)\n * Use when dependencies change and service needs to re-initialize\n */\n protected resetInitialization(): void {\n this.isInitialized = false;\n }\n\n /**\n * Override in subclasses to implement initialization logic\n */\n protected abstract doInitialize(): Promise<void>;\n\n /**\n * Override in subclasses to implement cleanup logic\n */\n protected abstract doCleanup(): void;\n}","/**\n * @file Organisation Service Provider\n * @package @jmruthers/pace-core\n * @module Providers/Services\n * @since 0.1.0\n *\n * React provider for OrganisationService.\n * Provides organisation service instance to React components.\n */\n\nimport React, { createContext, useMemo, useEffect, useRef } from 'react';\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { OrganisationService } from '../../services/OrganisationService';\nimport { logger } from '../../utils/core/logger';\n\n// Context type\nexport interface OrganisationServiceContextType {\n organisationService: OrganisationService;\n}\n\nexport const OrganisationServiceContext = createContext<OrganisationServiceContextType | null>(null);\n\nexport interface OrganisationServiceProviderProps {\n children: React.ReactNode;\n supabaseClient: SupabaseClient;\n user: User | null;\n session: Session | null;\n}\n\nexport function OrganisationServiceProvider({ \n children, \n supabaseClient, \n user, \n session \n}: OrganisationServiceProviderProps) {\n // Create service instance once with useRef to avoid recreation on auth state changes\n const organisationServiceRef = useRef<OrganisationService | null>(null);\n \n if (!organisationServiceRef.current) {\n organisationServiceRef.current = new OrganisationService(supabaseClient, user, session);\n }\n \n const organisationService = organisationServiceRef.current;\n\n // Update service dependencies when they change without recreation\n useEffect(() => {\n organisationService.updateDependencies(user, session);\n \n // Re-initialize service when user/session changes\n let isMounted = true;\n \n organisationService.initialize()\n .catch(error => {\n if (isMounted) {\n logger.error('OrganisationServiceProvider', 'Failed to initialize organisation service:', error);\n }\n });\n\n return () => {\n isMounted = false;\n };\n }, [organisationService, user, session]);\n\n // Cleanup service on unmount only\n useEffect(() => {\n return () => {\n organisationService.cleanup();\n };\n }, [organisationService]);\n\n const contextValue = useMemo(() => ({\n organisationService\n }), [organisationService]);\n\n return (\n <OrganisationServiceContext.Provider value={contextValue}>\n {children}\n </OrganisationServiceContext.Provider>\n );\n}","/**\n * @file Organisation Service\n * @package @jmruthers/pace-core\n * @module Services\n * @since 0.1.0\n *\n * Organisation service implementation.\n * Handles organisation management and selection with security-first approach.\n */\n\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { BaseService } from './base/BaseService';\nimport { IOrganisationService } from './interfaces/IOrganisationService';\nimport type {\n Organisation,\n OrganisationMembership,\n OrganisationSecurityError,\n OrganisationHierarchy\n} from '../types/organisation';\nimport { setOrganisationContext } from '../utils/context/organisationContext';\nimport { logger } from '../utils/core/logger';\nimport { assertUserId, assertOrganisationId } from '../types/core';\n\n// Type for RPC response from data_user_organisation_roles_get\ninterface OrganisationRoleRpcResponse {\n user_id: string;\n organisation_id: string;\n role: 'org_admin' | 'leader' | 'member' | 'supporter';\n status: 'active' | 'inactive' | 'suspended';\n [key: string]: unknown;\n}\n\nexport class OrganisationService extends BaseService implements IOrganisationService {\n private _selectedOrganisation: Organisation | null = null;\n private _organisations: Organisation[] = [];\n private _userMemberships: OrganisationMembership[] = [];\n private _roleMapState: Map<string, string> = new Map();\n private _isLoading = false;\n private _error: Error | null = null;\n private _isContextReady = false;\n private retryCount = 0;\n\n // Dependencies\n private supabaseClient: SupabaseClient | null = null;\n private user: User | null = null;\n private session: Session | null = null;\n\n // Internal state management\n private isLoadingRef = false;\n private lastLoadTimeRef = 0;\n private hasFailedRef = false;\n private abortControllerRef: AbortController | null = null;\n\n constructor(supabaseClient: SupabaseClient, user: User | null, session: Session | null) {\n super();\n this.supabaseClient = supabaseClient;\n this.user = user;\n this.session = session;\n }\n\n // Interface implementation\n getSelectedOrganisation(): Organisation | null { return this._selectedOrganisation; }\n getOrganisations(): Organisation[] { return this._organisations; }\n getUserMemberships(): OrganisationMembership[] { return this._userMemberships; }\n isLoading(): boolean { \n return this._isLoading;\n }\n getError(): Error | null { return this._error; }\n hasValidOrganisationContext(): boolean { return !!(this._selectedOrganisation && !this._isLoading && !this._error && this._isContextReady); }\n isContextReady(): boolean { return this._isContextReady; }\n\n // Additional methods for testing\n setSelectedOrganisation(organisation: Organisation | null): void {\n this._selectedOrganisation = organisation;\n if (organisation) {\n localStorage.setItem('pace-core-selected-organisation', JSON.stringify(organisation));\n this.setDatabaseOrganisationContext(organisation);\n } else {\n localStorage.removeItem('pace-core-selected-organisation');\n this._isContextReady = false;\n }\n this.notify();\n }\n\n // For testing: expose dependencies\n getDependencies(): { user: User | null; session: Session | null; supabaseClient: SupabaseClient | null } {\n return {\n user: this.user,\n session: this.session,\n supabaseClient: this.supabaseClient\n };\n }\n\n // For testing: manually set state\n setTestState(\n organisations: Organisation[],\n memberships: OrganisationMembership[],\n roleMap: Map<string, string>,\n selectedOrg: Organisation | null = null\n ): void {\n this._organisations = organisations;\n this._userMemberships = memberships;\n this._roleMapState = roleMap;\n if (selectedOrg) {\n this._selectedOrganisation = selectedOrg;\n } else if (organisations.length > 0) {\n this._selectedOrganisation = organisations[0];\n }\n this._isLoading = false;\n this._error = null;\n this.notify();\n }\n\n // Update dependencies\n updateDependencies(user: User | null, session: Session | null): void {\n const wasAuthenticated = !!(this.user && this.session);\n const isAuthenticated = !!(user && session);\n \n this.user = user;\n this.session = session;\n \n // If user logs out, allow re-initialization when they log back in\n if (wasAuthenticated && !isAuthenticated) {\n // Reset BaseService initialization state to allow re-initialization\n this.resetInitialization();\n }\n \n this.notify();\n }\n\n // Organisation methods\n async switchOrganisation(orgId: string): Promise<void> {\n // Validate access\n if (!this.validateOrganisationAccess(orgId)) {\n throw new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n }\n \n const targetOrg = this._organisations.find(org => org.id === orgId);\n if (!targetOrg) {\n throw new Error(`Organisation ${orgId} not found in user's organisations`) as OrganisationSecurityError;\n }\n \n this._selectedOrganisation = targetOrg;\n \n // Persist selection\n localStorage.setItem('pace-core-selected-organisation', JSON.stringify(targetOrg));\n \n // Set database organisation context\n await this.setDatabaseOrganisationContext(targetOrg);\n \n this.notify();\n }\n\n getUserRole(orgId?: string): string {\n const targetOrgId = orgId || this._selectedOrganisation?.id;\n if (!targetOrgId) return 'no_access';\n \n // Use roleMapState to get the role for this organisation\n return this._roleMapState.get(targetOrgId) || 'no_access';\n }\n\n validateOrganisationAccess(orgId: string): boolean {\n return this._userMemberships.some((m) => \n m.organisation_id === orgId && \n m.status === 'active' &&\n m.revoked_at === null\n );\n }\n\n async refreshOrganisations(): Promise<void> {\n if (!this.user || !this.session || !this.supabaseClient) return;\n \n // Force reload by triggering the effect\n this._isLoading = true;\n this.notify();\n await this.loadUserOrganisations();\n }\n\n ensureOrganisationContext(): Organisation {\n if (!this._selectedOrganisation) {\n throw new Error('Organisation context is required but not available') as OrganisationSecurityError;\n }\n return this._selectedOrganisation;\n }\n\n isOrganisationSecure(): boolean {\n return !!(this._selectedOrganisation && this.user);\n }\n\n getPrimaryOrganisation(): Organisation | null {\n // Look for org_admin role first, then leader, then member\n const rolePriority = ['org_admin', 'leader', 'member'] as const;\n \n for (const role of rolePriority) {\n const membership = this._userMemberships.find((m) => m.role === role);\n if (membership) {\n return this._organisations.find((org) => org.id === membership.organisation_id) || null;\n }\n }\n \n return null;\n }\n\n buildOrganisationHierarchy(orgs: Organisation[]): OrganisationHierarchy[] {\n const orgMap = new Map<string, Organisation>();\n orgs.forEach(org => orgMap.set(org.id, org));\n \n const roots: OrganisationHierarchy[] = [];\n \n orgs.forEach(org => {\n if (!org.parent_id) {\n // Root organisation\n roots.push({\n organisation: org,\n children: [],\n depth: 0\n });\n }\n });\n \n // For now, return flat structure - hierarchy building can be added later\n return roots;\n }\n\n // Lifecycle methods\n async initialize(): Promise<void> {\n await super.initialize();\n \n // Don't load if already loading (prevents duplicate loads during rapid auth events)\n if (!this.isLoadingRef) {\n await this.loadUserOrganisations();\n }\n }\n\n cleanup(): void {\n // Cleanup on unmount\n this.isLoadingRef = false;\n this.hasFailedRef = false;\n this.lastLoadTimeRef = 0;\n // Don't abort pending requests - let them complete naturally\n // Aborting causes React StrictMode issues where requests are cancelled mid-flight\n // The requests will complete on their own and update state if needed\n if (this.abortControllerRef) {\n // Clear the reference but don't abort - let requests complete\n this.abortControllerRef = null;\n }\n // Reset state\n this._selectedOrganisation = null;\n this._organisations = [];\n this._userMemberships = [];\n this._roleMapState = new Map();\n this._isLoading = false;\n this._error = null;\n this._isContextReady = false;\n super.cleanup();\n }\n\n protected async doInitialize(): Promise<void> {\n // Initial setup\n }\n\n protected doCleanup(): void {\n // Cleanup any resources\n }\n\n private async setDatabaseOrganisationContext(organisation: Organisation): Promise<void> {\n if (!this.supabaseClient || !this.session) {\n logger.warn('OrganisationService', 'No Supabase client or session available for setting organisation context');\n this._isContextReady = false;\n this.notify();\n return;\n }\n\n try {\n // Add timeout to prevent hanging\n const timeoutPromise = new Promise((_, reject) => {\n setTimeout(() => reject(new Error('Context setting timeout after 5 seconds')), 5000);\n });\n \n const contextPromise = setOrganisationContext(this.supabaseClient, organisation.id);\n \n await Promise.race([contextPromise, timeoutPromise]);\n \n // Database organisation context set successfully\n this._isContextReady = true;\n this.notify();\n } catch (error) {\n logger.error('OrganisationService', 'Failed to set database organisation context:', error);\n // Set context ready to true anyway - this is a non-critical operation\n // The app should still work without database context\n this._isContextReady = true;\n this.notify();\n // Don't throw - this is a non-critical operation\n }\n }\n\n private async loadUserOrganisations(): Promise<void> {\n if (!this.user || !this.session || !this.supabaseClient) {\n // Clear state when no user, session, or supabase client\n this._selectedOrganisation = null;\n this._organisations = [];\n this._userMemberships = [];\n this._isLoading = false;\n this._error = null;\n this.notify();\n return;\n }\n\n // Additional check to prevent loading during auth state changes\n if (this.isLoadingRef) {\n // Ensure loading state is correct\n this._isLoading = true;\n this.notify();\n return;\n }\n\n // Prevent rapid retries - minimum 2 seconds between attempts\n const now = Date.now();\n if (now - this.lastLoadTimeRef < 2000) {\n // Ensure loading state is correct\n if (this._organisations.length > 0 || this._selectedOrganisation) {\n this._isLoading = false;\n } else {\n this._isLoading = true;\n }\n this.notify();\n return;\n }\n\n // Cancel any existing request\n if (this.abortControllerRef) {\n this.abortControllerRef.abort();\n }\n\n // Create new abort controller for this request\n this.abortControllerRef = new AbortController();\n const abortSignal = this.abortControllerRef.signal;\n\n this.lastLoadTimeRef = now;\n this.isLoadingRef = true;\n this._isLoading = true;\n this._error = null;\n this.notify();\n \n try {\n // Get user's organisation memberships using secure RPC function\n // Include all roles (org_admin, leader, member, supporter) - supporters can access PORTAL\n let memberships, membershipError;\n try {\n // Add timeout and abort signal to prevent hanging RPC calls\n const timeoutPromise = new Promise((_, reject) => {\n const timeoutId = setTimeout(() => reject(new Error('RPC call timeout after 10 seconds')), 10000);\n abortSignal.addEventListener('abort', () => {\n clearTimeout(timeoutId);\n reject(new Error('Request aborted'));\n });\n });\n \n const rpcPromise = this.supabaseClient.rpc('data_user_organisation_roles_get', {\n p_user_id: this.user.id,\n p_organisation_id: null\n });\n \n // Check if request was aborted before making the call\n if (abortSignal.aborted) {\n throw new Error('Request aborted');\n }\n \n const result = await Promise.race([rpcPromise, timeoutPromise]) as { data: OrganisationRoleRpcResponse[] | null; error: Error | null };\n \n // Filter to organisation members (org_admin, leader, member, supporter)\n // Supporters are included to allow PORTAL access\n // Map to branded types when filtering\n memberships = result.data?.filter((role) => \n ['org_admin', 'leader', 'member', 'supporter'].includes(role.role)\n ).map((m) => ({\n ...m,\n user_id: assertUserId(m.user_id),\n organisation_id: assertOrganisationId(m.organisation_id),\n })) || [];\n membershipError = result.error;\n } catch (queryError) {\n membershipError = queryError instanceof Error ? queryError : new Error(String(queryError));\n }\n\n if (membershipError) {\n logger.error(\"OrganisationService\", \"Error loading memberships:\", membershipError);\n \n // If RPC fails with timeout, try direct database query as fallback\n if (membershipError.message?.includes('timeout')) {\n try {\n // Check if request was aborted before making fallback query\n if (abortSignal.aborted) {\n throw new Error('Request aborted');\n }\n\n const { data: fallbackData, error: fallbackError } = await this.supabaseClient\n .from('rbac_organisation_roles')\n .select(`\n id,\n user_id,\n organisation_id,\n role,\n status,\n granted_at,\n granted_by,\n revoked_at,\n revoked_by,\n notes,\n created_at,\n updated_at,\n organisations!inner(\n id,\n name,\n display_name,\n subscription_tier,\n settings,\n is_active,\n parent_id,\n created_at,\n updated_at\n )\n `)\n .eq('user_id', this.user.id)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member', 'supporter']);\n \n if (fallbackError) {\n logger.error(\"OrganisationService\", \"Fallback query also failed:\", fallbackError);\n throw membershipError; // Throw original error\n }\n \n // Map to branded types\n memberships = fallbackData?.map((m) => ({\n ...m,\n user_id: assertUserId(m.user_id),\n organisation_id: assertOrganisationId(m.organisation_id),\n })) || [];\n membershipError = null;\n } catch (fallbackErr) {\n logger.error(\"OrganisationService\", \"Fallback query failed:\", fallbackErr);\n throw membershipError; // Throw original error\n }\n } else {\n throw membershipError;\n }\n }\n \n if (!memberships || memberships.length === 0) {\n throw new Error('User has no active organisation memberships') as OrganisationSecurityError;\n }\n\n // Get organisation details for the memberships\n const organisationIds = memberships\n .map((m) => m.organisation_id)\n .filter((id: string) => {\n // Better validation to prevent empty string UUID errors\n if (!id || typeof id !== 'string') {\n logger.warn(\"OrganisationService\", \"Invalid organisation ID (not string):\", id);\n return false;\n }\n const trimmedId = id.trim();\n if (trimmedId === '') {\n logger.warn(\"OrganisationService\", \"Empty organisation ID found\");\n return false;\n }\n // Validate UUID format\n 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);\n if (!isValidUuid) {\n logger.warn(\"OrganisationService\", \"Invalid UUID format:\", trimmedId);\n }\n return isValidUuid;\n });\n \n if (organisationIds.length === 0) {\n logger.warn(\"OrganisationService\", \"No valid organisation IDs found in memberships:\", memberships);\n throw new Error('No valid organisation IDs found in memberships') as OrganisationSecurityError;\n }\n \n // Check if request was aborted before making organisations query\n if (abortSignal.aborted) {\n throw new Error('Request aborted');\n }\n \n const { data: allOrganisations, error: orgError } = await this.supabaseClient\n .from('organisations')\n .select('id, name, display_name, subscription_tier, settings, is_active, parent_id, created_at, updated_at');\n \n if (orgError) {\n logger.error(\"OrganisationService\", \"Error loading organisations:\", orgError);\n throw orgError;\n }\n \n // Filter manually on the client side\n const organisations = allOrganisations?.filter(org => \n organisationIds.includes(org.id)\n ) || [];\n\n // Create a map of organisation_id to role from the memberships data\n const roleMap = new Map<string, string>();\n memberships?.forEach((membership) => {\n roleMap.set(membership.organisation_id, membership.role);\n });\n\n // Extract organisations and memberships\n const orgs = organisations as Organisation[];\n const activeOrgs = orgs.filter(org => org.is_active);\n \n if (activeOrgs.length === 0) {\n throw new Error('User has no access to active organisations') as OrganisationSecurityError;\n }\n\n this._organisations = activeOrgs;\n // Memberships already have branded types from earlier mapping\n this._userMemberships = memberships as OrganisationMembership[];\n \n // Store role map in component state for later use\n this._roleMapState = roleMap;\n \n // Auto-select organisation: try persisted, then primary, then first\n let initialOrg: Organisation | null = null;\n let selectionMethod: 'persisted' | 'admin' | 'first' = 'first';\n \n // 1. Try to restore from localStorage\n try {\n const persistedOrgString = localStorage.getItem('pace-core-selected-organisation');\n if (persistedOrgString) {\n const persistedOrg = JSON.parse(persistedOrgString) as Organisation;\n // Validate persisted org ID before using it\n if (persistedOrg.id && typeof persistedOrg.id === 'string' && persistedOrg.id.trim() !== '') {\n const validPersistedOrg = activeOrgs.find(org => org.id === persistedOrg.id);\n if (validPersistedOrg) {\n initialOrg = validPersistedOrg;\n selectionMethod = 'persisted';\n } else {\n logger.warn(\"OrganisationService\", \"Persisted organisation not found in active orgs, clearing cache\");\n localStorage.removeItem('pace-core-selected-organisation');\n }\n } else {\n logger.warn(\"OrganisationService\", \"Invalid persisted organisation ID, clearing cache\");\n localStorage.removeItem('pace-core-selected-organisation');\n }\n }\n } catch (storageError) {\n logger.warn(\"OrganisationService\", \"Failed to restore persisted organisation:\", storageError);\n // Clear potentially corrupted cache\n localStorage.removeItem('pace-core-selected-organisation');\n }\n \n // 2. Fall back to org_admin role organisation (highest privilege)\n if (!initialOrg) {\n const adminMembership = memberships.find((m) => m.role === 'org_admin');\n if (adminMembership) {\n const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);\n if (foundOrg) {\n initialOrg = foundOrg;\n selectionMethod = 'admin';\n }\n }\n }\n \n // 3. Fall back to first organisation\n if (!initialOrg) {\n initialOrg = activeOrgs[0];\n selectionMethod = 'first';\n }\n \n if (!initialOrg) {\n throw new Error('No valid organisation found for user') as OrganisationSecurityError;\n }\n\n this._selectedOrganisation = initialOrg;\n \n // Persist selection\n localStorage.setItem('pace-core-selected-organisation', JSON.stringify(initialOrg));\n \n // Set database organisation context\n await this.setDatabaseOrganisationContext(initialOrg);\n \n // Reset retry count and failed flag on success\n this.retryCount = 0;\n this.hasFailedRef = false;\n \n } catch (err) {\n logger.error(\"OrganisationService\", \"Failed to load organisations:\", err);\n this._error = err as Error;\n // Increment retry count on error\n this.retryCount = this.retryCount + 1;\n // Set failed flag to prevent further attempts\n this.hasFailedRef = true;\n // Clear all cached data on error to prevent corruption\n this.clearAllCachedData();\n } finally {\n // Always cleanup refs and abort controller\n this.isLoadingRef = false;\n this._isLoading = false;\n this.abortControllerRef = null;\n this.notify();\n }\n }\n\n private clearAllCachedData(): void {\n localStorage.removeItem('pace-core-selected-organisation');\n localStorage.removeItem('pace-core-organisation-context');\n this._selectedOrganisation = null;\n this._organisations = [];\n this._userMemberships = [];\n this._roleMapState = new Map();\n this.retryCount = 0;\n this._isContextReady = false;\n // Don't clear _error here - let it persist for error reporting\n }\n}","/**\n * @file Event Service Provider\n * @package @jmruthers/pace-core\n * @module Providers/Services\n * @since 0.1.0\n *\n * React provider for EventService.\n * Provides event service instance to React components.\n */\n\nimport React, { createContext, useMemo, useEffect, useRef } from 'react';\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { EventService } from '../../services/EventService';\nimport { logger } from '../../utils/core/logger';\nimport type { Organisation } from '../../types/organisation';\n\n// Context type\nexport interface EventServiceContextType {\n eventService: EventService;\n}\n\nexport const EventServiceContext = createContext<EventServiceContextType | null>(null);\n\nexport interface EventServiceProviderProps {\n children: React.ReactNode;\n supabaseClient: SupabaseClient;\n user: User | null;\n session: Session | null;\n appName: string;\n selectedOrganisation: Organisation | null;\n setSelectedEventId: (eventId: string | null) => void;\n}\n\nexport function EventServiceProvider({ \n children, \n supabaseClient, \n user, \n session, \n appName,\n selectedOrganisation,\n setSelectedEventId\n}: EventServiceProviderProps) {\n // Create service instance once with useRef to avoid recreation on dependency changes\n const eventServiceRef = useRef<EventService | null>(null);\n \n if (!eventServiceRef.current) {\n eventServiceRef.current = new EventService(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);\n }\n \n const eventService = eventServiceRef.current;\n\n // Update service dependencies and initialize when dependencies change\n // Note: eventService is a ref and never changes, so we don't include it in dependencies\n useEffect(() => {\n let isMounted = true;\n \n const updateAndInitialize = async () => {\n // Update dependencies (now async to handle user change cleanup)\n await eventService.updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);\n \n if (!isMounted) return;\n \n // Re-initialize service when dependencies change\n await eventService.initialize().catch(error => {\n if (isMounted) {\n logger.error('EventServiceProvider', 'Failed to initialize event service:', error);\n }\n });\n };\n\n updateAndInitialize();\n\n return () => {\n isMounted = false;\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps\n // eventService is a ref and never changes, so we exclude it from dependencies\n }, [supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId]);\n\n // Cleanup service on unmount only\n useEffect(() => {\n return () => {\n eventService.cleanup();\n };\n }, [eventService]);\n\n const contextValue = useMemo(() => ({\n eventService\n }), [eventService]);\n\n return (\n <EventServiceContext.Provider value={contextValue}>\n {children}\n </EventServiceContext.Provider>\n );\n}","/**\n * @file Event Service\n * @package @jmruthers/pace-core\n * @module Services\n * @since 0.1.0\n *\n * Event service implementation.\n * Handles event management and selection with organisation context validation.\n */\n\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { BaseService } from './base/BaseService';\nimport { IEventService } from './interfaces/IEventService';\nimport { Event } from '../types/event';\nimport { Organisation } from '../types/organisation';\nimport { assertOrganisationId } from '../types/core';\nimport { logger } from '../utils/core/logger';\nimport { secureStorage } from '../utils/security/secureStorage';\n\nexport class EventService extends BaseService implements IEventService {\n private events: Event[] = [];\n private selectedEvent: Event | null = null;\n private _isLoading = false; // Start as false to avoid blocking UI\n private error: Error | null = null;\n\n // Dependencies\n private supabaseClient: SupabaseClient | null = null;\n private user: User | null = null;\n private session: Session | null = null;\n private appName: string = '';\n private selectedOrganisation: Organisation | null = null;\n private setSelectedEventId: ((eventId: string | null) => void) | null = null;\n\n // Internal state management\n private isInitializedRef = false;\n private isFetchingRef = false;\n private hasAutoSelectedRef = false;\n private userClearedEventRef = false;\n\n constructor(\n supabaseClient: SupabaseClient,\n user: User | null,\n session: Session | null,\n appName: string,\n selectedOrganisation: Organisation | null,\n setSelectedEventId: (eventId: string | null) => void\n ) {\n super();\n this.supabaseClient = supabaseClient;\n this.user = user;\n this.session = session;\n this.appName = appName;\n this.selectedOrganisation = selectedOrganisation;\n this.setSelectedEventId = setSelectedEventId;\n }\n\n // Helper method to get user-scoped storage key\n private getStorageKey(userId: string | null): string {\n if (!userId) {\n // Return a temporary key that won't match any user\n return 'pace-core-selected-event-no-user';\n }\n return `pace-core-selected-event-${userId}`;\n }\n\n // Update dependencies\n async updateDependencies(\n supabaseClient: SupabaseClient,\n user: User | null,\n session: Session | null,\n appName: string,\n selectedOrganisation: Organisation | null,\n setSelectedEventId: (eventId: string | null) => void\n ): Promise<void> {\n const previousOrgId = this.selectedOrganisation?.id;\n const newOrgId = selectedOrganisation?.id;\n const previousUserId = this.user?.id || null;\n const newUserId = user?.id || null;\n \n // If user changed, clear previous user's event selection from storage\n if (previousUserId !== newUserId) {\n if (previousUserId !== null) {\n await this.clearEventSelectionForUser(previousUserId);\n }\n // If user is now null (logout), clear current selection state\n if (newUserId === null) {\n this.selectedEvent = null;\n this.setSelectedEventId?.(null);\n }\n }\n \n this.supabaseClient = supabaseClient;\n this.user = user;\n this.session = session;\n this.appName = appName;\n this.selectedOrganisation = selectedOrganisation;\n this.setSelectedEventId = setSelectedEventId;\n \n // If organisation changed (from null to value, or different org), reset initialization\n // This ensures events are re-fetched when organisation context becomes available\n if (previousOrgId !== newOrgId) {\n this.resetInitialization(); // Reset BaseService's isInitialized flag\n this.isInitializedRef = false;\n this.isFetchingRef = false;\n // Clear events ONLY when switching between different organisations (not when org first becomes available)\n if (previousOrgId !== null && newOrgId !== null && previousOrgId !== newOrgId) {\n this.events = [];\n this.selectedEvent = null;\n } else if (previousOrgId !== null && newOrgId === null) {\n // Organisation was removed - clear events\n this.events = [];\n this.selectedEvent = null;\n }\n }\n \n this.notify();\n }\n\n // Event state getters\n getEvents(): Event[] {\n // Return a new array reference so React can detect changes\n // This ensures useMemo dependencies work correctly\n return [...this.events];\n }\n\n getSelectedEvent(): Event | null {\n return this.selectedEvent;\n }\n\n isLoading(): boolean {\n return this._isLoading;\n }\n\n getError(): Error | null {\n return this.error;\n }\n\n // Event methods\n setSelectedEvent(event: Event | null): void {\n if (event) {\n // SECURITY: Validate event belongs to current organisation\n try {\n if (this.selectedOrganisation && event.organisation_id !== this.selectedOrganisation.id) {\n logger.error('EventService', 'Event organisation_id does not match selected organisation', {\n eventOrganisationId: event.organisation_id,\n selectedOrganisationId: this.selectedOrganisation.id,\n eventName: event.event_name\n });\n return;\n }\n } catch (error) {\n logger.error('EventService', 'Error during event validation:', error);\n }\n\n this.selectedEvent = event;\n this.setSelectedEventId?.(event.event_id);\n // Persist asynchronously (don't await to avoid blocking)\n this.persistEventSelection(event.event_id).catch(error => {\n logger.warn('EventService', 'Failed to persist event selection:', error);\n });\n // Reset the user cleared flag when selecting an event\n this.userClearedEventRef = false;\n } else {\n this.selectedEvent = null;\n this.setSelectedEventId?.(null);\n // Clear from secure storage (don't await to avoid blocking)\n this.clearEventSelection().catch(error => {\n logger.warn('EventService', 'Failed to clear event selection:', error);\n });\n // Reset the auto-selection flag when clearing the event\n this.hasAutoSelectedRef = false;\n // Mark that user explicitly cleared the event to prevent auto-selection\n this.userClearedEventRef = true;\n }\n this.notify();\n }\n\n async refreshEvents(): Promise<void> {\n this.isInitializedRef = false;\n this.isFetchingRef = false;\n // Don't reset the user cleared flag - respect user's choice\n await this.fetchEvents();\n }\n\n async loadPersistedEvent(events: Event[]): Promise<boolean> {\n try {\n const userId = this.user?.id || null;\n \n // Don't load persisted event if no user is authenticated\n if (!userId) {\n return false;\n }\n \n const storageKey = this.getStorageKey(userId);\n \n // Retrieve from secure storage (will automatically decrypt)\n const persistedEventId = await secureStorage.getItem(storageKey);\n \n if (persistedEventId && events.length > 0) {\n // Validate that event exists in user's accessible events\n const persistedEvent = events.find(event => event.event_id === persistedEventId);\n \n if (persistedEvent) {\n // Use setSelectedEvent() to go through same path as EventSelector\n // This ensures consistent behavior and proper notification\n // Theme will be applied by useEventTheme hook once user navigates away from login\n this.setSelectedEvent(persistedEvent);\n return true;\n } else {\n // Event no longer accessible to user, clear invalid persisted event\n await secureStorage.removeItem(storageKey);\n }\n }\n } catch (error) {\n logger.warn('EventService', 'Failed to load persisted event:', error);\n }\n return false;\n }\n\n /**\n * Restore persisted event after login screen has rendered\n * This should be called explicitly from login page component\n * \n * @returns Promise<boolean> - true if event was successfully restored, false otherwise\n */\n async restorePersistedEvent(): Promise<boolean> {\n if (this.events.length === 0) {\n // Events haven't been fetched yet, wait for them\n return false;\n }\n return await this.loadPersistedEvent(this.events);\n }\n\n async persistEventSelection(eventId: string): Promise<void> {\n try {\n const userId = this.user?.id || null;\n const storageKey = this.getStorageKey(userId);\n \n // Store with encryption using secureStorage\n await secureStorage.setItem(storageKey, eventId, { encrypt: true });\n } catch (error) {\n logger.warn('EventService', 'Failed to persist event selection:', error);\n }\n }\n\n async clearEventSelection(): Promise<void> {\n try {\n const userId = this.user?.id || null;\n const storageKey = this.getStorageKey(userId);\n \n // Clear from secure storage\n await secureStorage.removeItem(storageKey);\n \n // Clear the selected event\n this.selectedEvent = null;\n this.setSelectedEventId?.(null);\n } catch (error) {\n logger.warn('EventService', 'Failed to clear event selection:', error);\n }\n }\n\n /**\n * Clear event selection for a specific user (used when user logs out or changes)\n */\n async clearEventSelectionForUser(userId: string | null): Promise<void> {\n try {\n if (!userId) return;\n \n const storageKey = this.getStorageKey(userId);\n await secureStorage.removeItem(storageKey);\n } catch (error) {\n logger.warn('EventService', 'Failed to clear event selection for user:', error);\n }\n }\n\n autoSelectNextEvent(events: Event[]): void {\n const nextEvent = this.getNextEventByDate(events);\n if (nextEvent) {\n // Use setSelectedEvent() to ensure consistent behavior\n // Theme will be applied by useEventTheme() hook\n this.setSelectedEvent(nextEvent);\n }\n }\n\n // Lifecycle methods\n async initialize(): Promise<void> {\n // Only call super.initialize() which will call doInitialize() and fetchEvents()\n // Don't call fetchEvents() again here to avoid double-fetching\n await super.initialize();\n }\n\n cleanup(): void {\n super.cleanup();\n }\n\n protected async doInitialize(): Promise<void> {\n // Skip if already initialized\n if (this.isInitializedRef) {\n return;\n }\n \n // Skip if already fetching\n if (this.isFetchingRef) {\n return;\n }\n \n // Clean up old storage keys (migration from old key format)\n try {\n sessionStorage.removeItem('pace-core-selected-event');\n localStorage.removeItem('pace-core-selected-event');\n localStorage.removeItem('_sec_pace-core-selected-event');\n } catch (error) {\n logger.warn('EventService', 'Failed to clean up old storage keys:', error);\n }\n \n // Skip if no user or organisation\n if (!this.user || !this.selectedOrganisation) {\n return;\n }\n \n // Initial setup - fetch events on initialization\n await this.fetchEvents(false);\n }\n\n protected doCleanup(): void {\n // Cleanup any resources\n }\n\n private async fetchEvents(skipLoadPersisted: boolean = false): Promise<void> {\n if (!this.user || !this.session || !this.supabaseClient || !this.appName || !this.selectedOrganisation) {\n // Already false from initialization, just notify\n this.notify();\n return;\n }\n \n // Only set loading to true if we actually have dependencies and are going to fetch\n this._isLoading = true;\n this.notify();\n\n // Prevent multiple simultaneous fetches\n if (this.isFetchingRef) {\n return;\n }\n\n this.isFetchingRef = true;\n let isMounted = true;\n\n try {\n // Call the RPC function following the established pattern\n const { data, error: rpcError } = await this.supabaseClient.rpc('data_user_events_get', {\n p_user_id: this.user.id,\n p_organisation_id: this.selectedOrganisation.id,\n p_app_name: this.appName\n });\n\n if (rpcError) {\n logger.error('EventService', 'RPC error fetching events:', rpcError);\n throw new Error(rpcError.message || 'Failed to fetch events');\n }\n\n if (isMounted) {\n const eventsData = data || [];\n\n // Transform the data to match our Event interface\n // Type for RPC response from data_user_events_get\n interface EventRpcResponse {\n event_id: string;\n event_name: string;\n event_code: string;\n event_date: string | null;\n event_venue: string | null;\n event_participants: number | null;\n event_colours: Record<string, unknown> | null;\n organisation_id: string;\n is_visible: boolean;\n }\n \n const transformedEvents: Event[] = eventsData.map((event: EventRpcResponse) => ({\n id: event.event_id,\n event_id: event.event_id,\n event_name: event.event_name,\n event_code: event.event_code,\n event_date: event.event_date,\n event_venue: event.event_venue,\n event_participants: event.event_participants,\n event_colours: event.event_colours,\n event_logo: '', // No logo field in event table\n organisation_id: assertOrganisationId(event.organisation_id),\n is_visible: event.is_visible,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString()\n }));\n\n this.events = transformedEvents;\n this.error = null;\n\n // Reset auto-selection ref for new events\n this.hasAutoSelectedRef = false;\n\n // Try to restore persisted event first (only if not skipping)\n if (!skipLoadPersisted) {\n const persistedEventLoaded = await this.loadPersistedEvent(transformedEvents);\n \n // If no persisted event was loaded and user hasn't explicitly cleared an event, auto-select the next event\n if (!persistedEventLoaded && !this.userClearedEventRef) {\n const nextEvent = this.getNextEventByDate(transformedEvents);\n if (nextEvent) {\n this.hasAutoSelectedRef = true;\n // Use setSelectedEvent() to ensure consistent behavior\n // Theme will be applied by useEventTheme() hook\n this.setSelectedEvent(nextEvent);\n }\n }\n } else {\n // If skipping persisted event load, still do auto-selection for new users\n if (!this.userClearedEventRef) {\n const nextEvent = this.getNextEventByDate(transformedEvents);\n if (nextEvent) {\n this.hasAutoSelectedRef = true;\n // Use setSelectedEvent() to ensure consistent behavior\n // Theme will be applied by useEventTheme() hook\n this.setSelectedEvent(nextEvent);\n }\n }\n }\n }\n } catch (err) {\n logger.error('EventService', 'Error fetching events:', err);\n const _error = err instanceof Error ? err : new Error('Unknown error occurred');\n \n if (isMounted) {\n this.error = _error;\n this.events = [];\n }\n } finally {\n if (isMounted) {\n this._isLoading = false;\n }\n this.isFetchingRef = false;\n this.notify();\n }\n }\n\n\n getNextEventByDate(events?: Event[]): Event | null {\n const eventsToUse = events || this.events;\n if (!eventsToUse || eventsToUse.length === 0) {\n return null;\n }\n\n // Get start of today (midnight) to compare dates only (ignore time)\n const now = new Date();\n const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();\n \n const futureEvents = eventsToUse.filter(event => {\n if (!event.event_date) return false;\n const eventDate = new Date(event.event_date);\n // Compare by date only (start of day), not by time\n const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();\n return startOfEventDate >= startOfToday;\n });\n\n if (futureEvents.length > 0) {\n // Sort by date (ascending) to get the next event\n const sortedFutureEvents = futureEvents.sort((a, b) => {\n const dateA = new Date(a.event_date!);\n const dateB = new Date(b.event_date!);\n return dateA.getTime() - dateB.getTime();\n });\n\n return sortedFutureEvents[0];\n }\n\n // Fallback: If no future events found, return the most recent past event\n // This handles cases where users only have access to past events\n const pastEvents = eventsToUse.filter(event => {\n if (!event.event_date) return false;\n const eventDate = new Date(event.event_date);\n const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();\n return startOfEventDate < startOfToday;\n });\n\n if (pastEvents.length > 0) {\n // Sort by date (descending) to get the most recent past event\n const sortedPastEvents = pastEvents.sort((a, b) => {\n const dateA = new Date(a.event_date!);\n const dateB = new Date(b.event_date!);\n return dateB.getTime() - dateA.getTime(); // Descending order\n });\n\n return sortedPastEvents[0];\n }\n\n // No events found at all\n return null;\n }\n}","/**\n * @file Inactivity Service Provider\n * @package @jmruthers/pace-core\n * @module Providers/Services\n * @since 0.1.0\n *\n * React provider for InactivityService.\n * Provides inactivity service instance to React components.\n */\n\nimport React, { createContext, useMemo, useEffect, useRef } from 'react';\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { InactivityService } from '../../services/InactivityService';\nimport { logger } from '../../utils/core/logger';\n\n// Context type\nexport interface InactivityServiceContextType {\n inactivityService: InactivityService;\n}\n\nexport const InactivityServiceContext = createContext<InactivityServiceContextType | null>(null);\n\nexport interface InactivityServiceProviderProps {\n children: React.ReactNode;\n supabaseClient: SupabaseClient;\n user: User | null;\n session: Session | null;\n idleTimeoutMs?: number;\n warnBeforeMs?: number;\n onIdleLogout: (reason: 'inactivity') => void;\n}\n\nexport function InactivityServiceProvider({ \n children, \n supabaseClient, \n user, \n session, \n idleTimeoutMs = 30 * 60 * 1000,\n warnBeforeMs = 60 * 1000,\n onIdleLogout\n}: InactivityServiceProviderProps) {\n // Create service instance once with useRef to avoid recreation on dependency changes\n const inactivityServiceRef = useRef<InactivityService | null>(null);\n \n if (!inactivityServiceRef.current) {\n inactivityServiceRef.current = new InactivityService(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout);\n }\n \n const inactivityService = inactivityServiceRef.current;\n\n // Update service dependencies and initialize when dependencies change\n useEffect(() => {\n inactivityService.updateDependencies(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout);\n \n // Re-initialize service when dependencies change\n let isMounted = true;\n \n inactivityService.initialize().catch(error => {\n if (isMounted) {\n logger.error('InactivityServiceProvider', 'Failed to initialize inactivity service:', error);\n }\n });\n\n return () => {\n isMounted = false;\n };\n }, [inactivityService, supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout]);\n\n // Cleanup service on unmount only\n useEffect(() => {\n return () => {\n inactivityService.cleanup();\n };\n }, [inactivityService]);\n\n const contextValue = useMemo(() => ({\n inactivityService\n }), [inactivityService]);\n\n return (\n <InactivityServiceContext.Provider value={contextValue}>\n {children}\n </InactivityServiceContext.Provider>\n );\n}","/**\n * @file Inactivity Service\n * @package @jmruthers/pace-core\n * @module Services\n * @since 0.1.0\n *\n * Inactivity service implementation.\n * Handles inactivity tracking, auto-logout, and warning modals.\n */\n\nimport { type SupabaseClient, type User, type Session } from '@supabase/supabase-js';\nimport { BaseService } from './base/BaseService';\nimport { IInactivityService } from './interfaces/IInactivityService';\nimport { logger } from '../utils/core/logger';\n\ninterface InactivityTracker {\n isIdle: boolean;\n timeRemaining: number;\n showWarning: boolean;\n isTracking: boolean;\n resetActivity: () => void;\n startTracking: () => void;\n stopTracking: () => void;\n cleanup?: () => void;\n}\n\nexport class InactivityService extends BaseService implements IInactivityService {\n private _showInactivityWarning = false;\n private _inactivityTimeRemaining = 0;\n private _isIdle = false;\n private _timeRemaining = 0;\n private _showWarning = false;\n private _isTracking = false;\n\n // Dependencies\n private supabaseClient: SupabaseClient | null = null;\n private user: User | null = null;\n private session: Session | null = null;\n private idleTimeoutMs = 30 * 60 * 1000; // 30 minutes\n private warnBeforeMs = 60 * 1000; // 60 seconds\n private onIdleLogout: ((reason: 'inactivity') => void) | null = null;\n\n // Internal state management\n private inactivityTracker: InactivityTracker | null = null;\n private isInactivityEnabled = true;\n private cleanupHandlers: (() => void) | null = null;\n\n constructor(\n supabaseClient: SupabaseClient | null,\n user: User | null,\n session: Session | null,\n idleTimeoutMs: number = 30 * 60 * 1000,\n warnBeforeMs: number = 60 * 1000,\n onIdleLogout: (reason: 'inactivity') => void\n ) {\n super();\n this.supabaseClient = supabaseClient;\n this.user = user;\n this.session = session;\n this.idleTimeoutMs = idleTimeoutMs;\n this.warnBeforeMs = warnBeforeMs;\n this.onIdleLogout = onIdleLogout;\n \n // Initialize time remaining to idle timeout\n this._timeRemaining = idleTimeoutMs;\n }\n\n // Interface implementation\n isIdle(): boolean { return this._isIdle; }\n getTimeRemaining(): number { return this._timeRemaining; }\n isWarningShown(): boolean { return this._showWarning; }\n isTracking(): boolean { return this._isTracking; }\n getShowInactivityWarning(): boolean { return this._showInactivityWarning; }\n getInactivityTimeRemaining(): number { return this._inactivityTimeRemaining; }\n\n // Additional getter methods that tests expect\n getIsIdle(): boolean { return this._isIdle; }\n getIsTracking(): boolean { return this._isTracking; }\n getShowWarning(): boolean { return this._showWarning; }\n\n // Additional methods for testing\n setShowInactivityWarning(value: boolean): void {\n this._showInactivityWarning = value;\n this.notify();\n }\n\n setInactivityTimeRemaining(value: number): void {\n this._inactivityTimeRemaining = value;\n this.notify();\n }\n\n setIsIdle(value: boolean): void {\n this._isIdle = value;\n this.notify();\n }\n\n setTimeRemaining(value: number): void {\n this._timeRemaining = value;\n this.notify();\n }\n\n setShowWarning(value: boolean): void {\n this._showWarning = value;\n this.notify();\n }\n\n setIsTracking(value: boolean): void {\n this._isTracking = value;\n this.notify();\n }\n\n triggerWarning(timeRemaining: number): void {\n this._showInactivityWarning = true;\n this._inactivityTimeRemaining = Math.ceil(timeRemaining / 1000);\n this._showWarning = true;\n this.notify();\n }\n\n triggerIdle(): void {\n this._isIdle = true;\n this.handleIdleLogout();\n this.notify();\n }\n\n // Update dependencies\n updateDependencies(\n supabaseClient: SupabaseClient | null,\n user: User | null,\n session: Session | null,\n idleTimeoutMs?: number,\n warnBeforeMs?: number,\n onIdleLogout?: (reason: 'inactivity') => void\n ): void {\n this.supabaseClient = supabaseClient;\n this.user = user;\n this.session = session;\n if (idleTimeoutMs !== undefined) this.idleTimeoutMs = idleTimeoutMs;\n if (warnBeforeMs !== undefined) this.warnBeforeMs = warnBeforeMs;\n if (onIdleLogout !== undefined) this.onIdleLogout = onIdleLogout;\n this.notify();\n }\n\n // Inactivity methods\n resetActivity(): void {\n if (this.inactivityTracker) {\n this.inactivityTracker.resetActivity();\n }\n this._isIdle = false;\n this._showWarning = false;\n this._showInactivityWarning = false;\n this._inactivityTimeRemaining = 0;\n this._timeRemaining = this.idleTimeoutMs;\n this.notify();\n }\n\n startTracking(): void {\n if (this.inactivityTracker) {\n this.inactivityTracker.startTracking();\n }\n this._isTracking = true;\n this.notify();\n }\n\n stopTracking(): void {\n if (this.inactivityTracker) {\n this.inactivityTracker.stopTracking();\n }\n this._isTracking = false;\n this.notify();\n }\n\n async handleIdleLogout(): Promise<void> {\n // Hide warning\n this._showInactivityWarning = false;\n this._inactivityTimeRemaining = 0;\n \n // Stop tracking\n this.stopTracking();\n \n // Sign out via Supabase\n try {\n if (this.supabaseClient) {\n await this.supabaseClient.auth.signOut();\n }\n } catch (error) {\n logger.error('InactivityService', 'Error during idle logout:', error);\n }\n \n // Call app callback for navigation/redirect\n this.onIdleLogout?.('inactivity');\n this.notify();\n }\n\n handleStaySignedIn(): void {\n this._showInactivityWarning = false;\n this._inactivityTimeRemaining = 0;\n this.resetActivity();\n this.notify();\n }\n\n async handleSignOutNow(): Promise<void> {\n this._showInactivityWarning = false;\n this._inactivityTimeRemaining = 0;\n this.stopTracking();\n \n // Sign out via Supabase\n try {\n if (this.supabaseClient) {\n await this.supabaseClient.auth.signOut();\n }\n } catch (error) {\n logger.error('InactivityService', 'Error during manual sign out:', error);\n }\n \n // Call app callback for navigation/redirect\n this.onIdleLogout?.('inactivity');\n this.notify();\n }\n\n // Lifecycle methods\n async initialize(): Promise<void> {\n await super.initialize();\n await this.setupInactivityTracker();\n }\n\n cleanup(): void {\n if (this.cleanupHandlers) {\n this.cleanupHandlers();\n this.cleanupHandlers = null;\n }\n if (this.inactivityTracker) {\n this.inactivityTracker = null;\n }\n this._isTracking = false;\n this._isIdle = false;\n this._showWarning = false;\n this._showInactivityWarning = false;\n this._timeRemaining = 0;\n this._inactivityTimeRemaining = 0;\n super.cleanup();\n }\n\n protected async doInitialize(): Promise<void> {\n // Production safety check for inactivity feature\n if (typeof window !== 'undefined') {\n const isProduction = import.meta.env.MODE === 'production';\n \n if (isProduction) {\n logger.warn('InactivityService', 'Inactivity feature enabled in production');\n }\n }\n }\n\n protected doCleanup(): void {\n // Cleanup any resources\n }\n\n private async setupInactivityTracker(): Promise<void> {\n if (typeof window === 'undefined') return;\n\n // Check if inactivity is enabled\n this.isInactivityEnabled = !!(this.user && this.session);\n\n if (!this.isInactivityEnabled) {\n return;\n }\n\n // Set up event handlers directly (no need to import hooks - services are pure TypeScript)\n this.setupEventHandlers();\n }\n\n private setupEventHandlers(): void {\n if (typeof window === 'undefined') return;\n\n let idleTimer: NodeJS.Timeout | null = null;\n let warningTimer: NodeJS.Timeout | null = null;\n let lastActivity = Date.now();\n\n const resetTimers = () => {\n lastActivity = Date.now();\n \n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n \n if (warningTimer) {\n clearTimeout(warningTimer);\n warningTimer = null;\n }\n\n this._showInactivityWarning = false;\n this._inactivityTimeRemaining = 0;\n this._isIdle = false;\n this._showWarning = false;\n this.notify();\n };\n\n const startIdleTimer = () => {\n if (idleTimer) {\n clearTimeout(idleTimer);\n }\n\n idleTimer = setTimeout(() => {\n this._isIdle = true;\n this._showWarning = true;\n this.notify();\n \n // Start warning timer\n warningTimer = setTimeout(() => {\n this.handleIdleLogout();\n }, this.warnBeforeMs);\n }, this.idleTimeoutMs - this.warnBeforeMs);\n };\n\n const startWarningTimer = () => {\n if (warningTimer) {\n clearTimeout(warningTimer);\n }\n\n warningTimer = setTimeout(() => {\n this.handleIdleLogout();\n }, this.warnBeforeMs);\n };\n\n // Activity detection\n const activityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];\n \n const handleActivity = () => {\n resetTimers();\n startIdleTimer();\n };\n\n // Add event listeners\n activityEvents.forEach(event => {\n document.addEventListener(event, handleActivity, true);\n });\n\n // Start initial timer\n startIdleTimer();\n\n // Store cleanup function\n this.cleanupHandlers = () => {\n if (idleTimer) {\n clearTimeout(idleTimer);\n idleTimer = null;\n }\n \n if (warningTimer) {\n clearTimeout(warningTimer);\n warningTimer = null;\n }\n\n activityEvents.forEach(event => {\n document.removeEventListener(event, handleActivity, true);\n });\n\n this._isTracking = false;\n this._isIdle = false;\n this._showWarning = false;\n this._timeRemaining = 0;\n this._showInactivityWarning = false;\n this._inactivityTimeRemaining = 0;\n };\n\n this._isTracking = true;\n this.notify();\n }\n}","/**\n * @file Auth Service Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Services\n * @since 0.1.0\n *\n * React hook for AuthService.\n * Provides authentication service with reactive state updates.\n */\n\nimport { useContext, useReducer, useEffect } from 'react';\nimport { AuthServiceContext } from '../../providers/services/AuthServiceProvider';\nimport { AuthService } from '../../services/AuthService';\n\nexport function useAuthService(): AuthService {\n const context = useContext(AuthServiceContext);\n \n if (!context) {\n throw new Error('useAuthService must be used within AuthServiceProvider');\n }\n \n // Subscribe to service state changes\n const [, forceUpdate] = useReducer(x => x + 1, 0);\n \n useEffect(() => {\n return context.authService.subscribe(() => forceUpdate());\n }, [context.authService]);\n \n return context.authService;\n}","/**\n * @file Organisation Service Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Services\n * @since 0.1.0\n *\n * React hook for OrganisationService.\n * Provides organisation service with reactive state updates.\n */\n\nimport { useContext, useReducer, useEffect } from 'react';\nimport { OrganisationServiceContext } from '../../providers/services/OrganisationServiceProvider';\nimport { OrganisationService } from '../../services/OrganisationService';\n\nexport function useOrganisationService(): OrganisationService {\n const context = useContext(OrganisationServiceContext);\n \n if (!context) {\n throw new Error('useOrganisationService must be used within OrganisationServiceProvider');\n }\n \n // Subscribe to service state changes\n const [, forceUpdate] = useReducer(x => x + 1, 0);\n \n useEffect(() => {\n return context.organisationService.subscribe(() => forceUpdate());\n }, [context.organisationService]);\n \n return context.organisationService;\n}","/**\n * @file Event Service Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Services\n * @since 0.1.0\n *\n * React hook for EventService.\n * Provides event service with reactive state updates.\n */\n\nimport { useContext, useReducer, useEffect } from 'react';\nimport { EventServiceContext } from '../../providers/services/EventServiceProvider';\nimport { EventService } from '../../services/EventService';\n\nexport function useEventService(): EventService {\n const context = useContext(EventServiceContext);\n \n if (!context) {\n throw new Error('useEventService must be used within EventServiceProvider');\n }\n \n // Subscribe to service state changes\n const [, forceUpdate] = useReducer(x => x + 1, 0);\n \n useEffect(() => {\n return context.eventService.subscribe(() => forceUpdate());\n }, [context.eventService]);\n \n return context.eventService;\n}","/**\n * @file Inactivity Service Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Services\n * @since 0.1.0\n *\n * React hook for InactivityService.\n * Provides inactivity service with reactive state updates.\n */\n\nimport { useContext, useReducer, useEffect } from 'react';\nimport { InactivityServiceContext } from '../../providers/services/InactivityServiceProvider';\nimport { InactivityService } from '../../services/InactivityService';\n\nexport function useInactivityService(): InactivityService {\n const context = useContext(InactivityServiceContext);\n \n if (!context) {\n throw new Error('useInactivityService must be used within InactivityServiceProvider');\n }\n \n // Subscribe to service state changes\n const [, forceUpdate] = useReducer(x => x + 1, 0);\n \n useEffect(() => {\n return context.inactivityService.subscribe(() => forceUpdate());\n }, [context.inactivityService]);\n \n return context.inactivityService;\n}","/**\n * @file useSessionRestoration Hook\n * @package @jmruthers/pace-core\n * @module Hooks\n * @since 0.1.0\n *\n * Provides reactive session restoration state from the AuthService.\n * Handles timeout detection to prevent infinite loading loops when\n * Supabase session hydration from localStorage takes too long.\n */\n\nimport { useContext, useMemo, useEffect, useState } from 'react';\nimport { AuthServiceContext } from '../providers/services/AuthServiceProvider';\nimport type { SessionRestorationState } from '../types/auth';\nimport { createLogger } from '../utils/core/logger';\n\nconst log = createLogger('useSessionRestoration');\n\nconst SESSION_RESTORATION_TIMEOUT_MS = 5000;\n\nexport interface UseSessionRestorationResult extends SessionRestorationState {\n /** Indicates whether the restoration process exceeded the timeout window */\n hasTimedOut: boolean;\n /** Timeout duration in milliseconds */\n timeoutMs: number;\n}\n\nexport function useSessionRestoration(): UseSessionRestorationResult {\n const context = useContext(AuthServiceContext);\n\n if (!context) {\n throw new Error('useSessionRestoration must be used within AuthServiceProvider');\n }\n\n const { sessionRestoration } = context;\n const [hasTimedOut, setHasTimedOut] = useState(false);\n\n useEffect(() => {\n let timeoutHandle: ReturnType<typeof setTimeout> | null = null;\n\n if (sessionRestoration.isRestoring && !sessionRestoration.restorationComplete && !sessionRestoration.restorationError) {\n setHasTimedOut(false);\n timeoutHandle = setTimeout(() => {\n log.warn('Session restoration timed out');\n setHasTimedOut(true);\n }, SESSION_RESTORATION_TIMEOUT_MS);\n } else {\n setHasTimedOut(false);\n }\n\n return () => {\n if (timeoutHandle) {\n clearTimeout(timeoutHandle);\n }\n };\n }, [\n sessionRestoration.isRestoring,\n sessionRestoration.restorationComplete,\n sessionRestoration.restorationError\n ]);\n\n return useMemo(() => ({\n ...sessionRestoration,\n hasTimedOut,\n timeoutMs: SESSION_RESTORATION_TIMEOUT_MS,\n }), [sessionRestoration, hasTimedOut]);\n}\n"],"mappings":"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","names":["createContext","useContext","useMemo","useRef","useEffect","useState","useReducer","error","createContext","useMemo","useEffect","jsx","createContext","useEffect","useMemo","createContext","useMemo","useEffect","useRef","jsx","createContext","useRef","useEffect","useMemo","createContext","useMemo","useEffect","useRef","jsx","createContext","useRef","useEffect","useMemo","useEffect","useEffect","useContext","useReducer","useEffect","useContext","useReducer","useEffect","useContext","useReducer","useEffect","useContext","useReducer","useEffect","useContext","useReducer","useEffect","useContext","useReducer","useEffect","useContext","useMemo","useEffect","useState","useContext","useState","useEffect","useMemo","jsx","createContext","useContext","useMemo","useState","useRef","useEffect","useReducer"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/request-deduplication.ts","../src/utils/google-places/loadGoogleMapsScript.ts","../src/utils/google-places/googlePlacesUtils.ts","../src/utils/performance/performanceBudgets.ts"],"sourcesContent":["/**\n * Request Deduplication Utility\n * @package @jmruthers/pace-core\n * @module Utils/RequestDeduplication\n * @since 2.0.0\n * \n * Provides request deduplication to prevent duplicate in-flight requests.\n * When multiple components request the same data simultaneously, only one\n * request is made and all callers share the same promise.\n */\n\nimport { createLogger } from './core/logger';\n\nconst log = createLogger('request-deduplication');\n\n/**\n * In-flight request cache\n * Key: request identifier (e.g., \"GET:table:filter:value\")\n * Value: Promise that resolves to the request result\n */\nconst inFlightRequests = new Map<string, Promise<any>>();\n\n/**\n * Generate a request key from request parameters\n * \n * @param method - HTTP method (GET, POST, etc.)\n * @param table - Table name\n * @param filters - Filter object\n * @param select - Select columns\n * @returns Request key string\n */\nexport function generateRequestKey(\n method: string,\n table: string,\n filters?: Record<string, any>,\n select?: string\n): string {\n const filterStr = filters ? JSON.stringify(filters) : '';\n const selectStr = select || '*';\n return `${method}:${table}:${filterStr}:${selectStr}`;\n}\n\n/**\n * Get or create a request\n * \n * If a request with the same key is already in-flight, returns the existing promise.\n * Otherwise, creates a new request and stores it for deduplication.\n * \n * @param key - Request key\n * @param requestFn - Function that performs the actual request\n * @returns Promise that resolves to the request result\n * \n * @example\n * ```ts\n * const data = await getOrCreateRequest(\n * 'GET:pace_person:{\"user_id\":\"123\"}',\n * async () => {\n * const { data } = await supabase\n * .from('pace_person')\n * .select('id, first_name')\n * .eq('user_id', '123')\n * .single();\n * return data;\n * }\n * );\n * ```\n */\nexport async function getOrCreateRequest<T>(\n key: string,\n requestFn: () => Promise<T>\n): Promise<T> {\n // Check if request is already in-flight\n const existingRequest = inFlightRequests.get(key);\n if (existingRequest) {\n log.debug(`Request deduplication: reusing in-flight request for ${key}`);\n return existingRequest as Promise<T>;\n }\n \n // Create new request\n log.debug(`Creating new request for ${key}`);\n const requestPromise = requestFn()\n .then((result) => {\n // Remove from in-flight cache after completion\n inFlightRequests.delete(key);\n return result;\n })\n .catch((error) => {\n // Remove from in-flight cache on error\n inFlightRequests.delete(key);\n throw error;\n });\n \n // Store in-flight request\n inFlightRequests.set(key, requestPromise);\n \n return requestPromise;\n}\n\n/**\n * Clear all in-flight requests\n * \n * Useful for cleanup or testing.\n */\nexport function clearInFlightRequests(): void {\n const count = inFlightRequests.size;\n inFlightRequests.clear();\n log.debug(`Cleared ${count} in-flight requests`);\n}\n\n/**\n * Get statistics about in-flight requests\n * \n * @returns Statistics object\n */\nexport function getInFlightRequestStats(): {\n count: number;\n keys: string[];\n} {\n return {\n count: inFlightRequests.size,\n keys: Array.from(inFlightRequests.keys()),\n };\n}\n\n/**\n * Supabase query wrapper with automatic deduplication\n * \n * Wraps a Supabase query to automatically deduplicate identical requests.\n * \n * @param supabase - Supabase client\n * @param table - Table name\n * @param filters - Filter object (e.g., { user_id: '123' })\n * @param select - Select columns (default: '*')\n * @param requestFn - Function that performs the query\n * @returns Promise that resolves to query result\n * \n * @example\n * ```ts\n * const person = await deduplicatedQuery(\n * supabase,\n * 'pace_person',\n * { user_id: userId },\n * 'id, first_name, last_name',\n * async () => {\n * const { data } = await supabase\n * .from('pace_person')\n * .select('id, first_name, last_name')\n * .eq('user_id', userId)\n * .single();\n * return data;\n * }\n * );\n * ```\n */\nexport async function deduplicatedQuery<T>(\n supabase: any,\n table: string,\n filters: Record<string, any>,\n select: string,\n requestFn: () => Promise<T>\n): Promise<T> {\n const key = generateRequestKey('GET', table, filters, select);\n return getOrCreateRequest(key, requestFn);\n}\n\n","/**\n * @file Google Maps Script Loader\n * @package @jmruthers/pace-core\n * @module Utils/GooglePlaces\n * @since 0.1.0\n *\n * Utility to dynamically load the Google Maps JavaScript API.\n * This is required because the REST API doesn't support CORS from browsers.\n */\n\n// Type definitions for Google Maps (minimal, just what we need)\ndeclare global {\n interface Window {\n google?: {\n maps: {\n places: {\n // New AutocompleteSuggestion API (recommended)\n AutocompleteSuggestion: {\n fetchAutocompleteSuggestions: (\n request: {\n input: string;\n includedRegionCodes?: string[];\n locationBias?: {\n circle?: {\n center: { latitude: number; longitude: number };\n radius: number;\n };\n };\n includedPrimaryTypes?: string[];\n languageCode?: string;\n }\n ) => Promise<{\n suggestions: Array<{\n placePrediction?: {\n placeId: string;\n text: {\n text: string;\n matches: Array<{\n endOffset: number;\n startOffset: number;\n }>;\n };\n structuredFormat?: {\n mainText: { text: string };\n secondaryText: { text: string };\n };\n };\n }>;\n }>;\n };\n // Legacy AutocompleteService (deprecated but still works)\n AutocompleteService: new () => {\n getPlacePredictions: (\n request: {\n input: string;\n componentRestrictions?: { country: string | string[] };\n location?: { lat: () => number; lng: () => number };\n radius?: number;\n types?: string[];\n language?: string;\n },\n callback: (\n predictions: Array<{\n description: string;\n place_id: string;\n structured_formatting: {\n main_text: string;\n secondary_text: string;\n };\n }> | null,\n status: string\n ) => void\n ) => void;\n };\n PlacesService: new (element: HTMLElement) => {\n getDetails: (\n request: { placeId: string; fields?: string[] },\n callback: (\n place: {\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n } | null,\n status: string\n ) => void\n ) => void;\n };\n PlacesServiceStatus: {\n OK: string;\n ZERO_RESULTS: string;\n NOT_FOUND: string;\n REQUEST_DENIED: string;\n INVALID_REQUEST: string;\n OVER_QUERY_LIMIT: string;\n };\n };\n LatLng: new (lat: number, lng: number) => { lat: () => number; lng: () => number };\n };\n };\n }\n}\n\n/**\n * Load Google Maps JavaScript API script\n * @param apiKey - Google Places API key\n * @param libraries - Comma-separated list of libraries to load (default: 'places')\n * @returns Promise that resolves when the script is loaded\n */\nexport function loadGoogleMapsScript(\n apiKey: string,\n libraries: string = 'places'\n): Promise<void> {\n return new Promise((resolve, reject) => {\n // Check if script is already loaded\n if (window.google && window.google.maps && window.google.maps.places) {\n resolve();\n return;\n }\n\n // Check if script is already being loaded\n const existingScript = document.querySelector(\n `script[src*=\"maps.googleapis.com/maps/api/js\"]`\n );\n if (existingScript) {\n // Wait for existing script to load\n existingScript.addEventListener('load', () => {\n // Wait for the library to initialize with multiple retries\n let attempts = 0;\n const maxAttempts = 20; // 2 seconds total\n \n const checkPlaces = () => {\n if (window.google?.maps?.places) {\n resolve();\n } else if (attempts < maxAttempts) {\n attempts++;\n setTimeout(checkPlaces, 100);\n } else {\n reject(new Error('Google Maps script loaded but Places library not available. Make sure the Places API is enabled in your Google Cloud Console.'));\n }\n };\n \n checkPlaces();\n });\n existingScript.addEventListener('error', () => {\n reject(new Error('Failed to load Google Maps script'));\n });\n return;\n }\n\n // Create and load script\n const script = document.createElement('script');\n script.src = `https://maps.googleapis.com/maps/api/js?key=${apiKey}&libraries=${libraries}&loading=async`;\n script.async = true;\n script.defer = true;\n\n script.onload = () => {\n // Wait for the library to initialize with multiple retries\n let attempts = 0;\n const maxAttempts = 20; // 2 seconds total (20 * 100ms)\n \n const checkPlaces = () => {\n if (window.google?.maps?.places) {\n resolve();\n } else if (attempts < maxAttempts) {\n attempts++;\n setTimeout(checkPlaces, 100);\n } else {\n // Check if google.maps exists but places doesn't\n if (window.google?.maps && !window.google.maps.places) {\n reject(new Error('Google Maps loaded but Places library not available. Make sure the Places API is enabled in your Google Cloud Console and the \"places\" library is included in the script URL.'));\n } else if (!window.google) {\n reject(new Error('Google Maps script loaded but google object not available. Check your API key and network connection.'));\n } else {\n reject(new Error('Google Maps script loaded but Places library not available after multiple attempts. Make sure the Places API is enabled in your Google Cloud Console.'));\n }\n }\n };\n \n // Start checking immediately, then retry if needed\n checkPlaces();\n };\n\n script.onerror = () => {\n reject(new Error('Failed to load Google Maps script'));\n };\n\n document.head.appendChild(script);\n });\n}\n\n/**\n * Check if Google Maps is already loaded\n */\nexport function isGoogleMapsLoaded(): boolean {\n return !!(window.google && window.google.maps && window.google.maps.places);\n}\n\n","/**\n * @file Google Places API Utilities\n * @package @jmruthers/pace-core\n * @module Utils/GooglePlaces\n * @since 0.1.0\n *\n * Utility functions for interacting with Google Places API.\n * Uses the Google Maps JavaScript API to avoid CORS issues.\n *\n * Features:\n * - Places Autocomplete Service integration\n * - Places Service integration\n * - Address component parsing\n * - Error handling\n * - Request deduplication\n */\n\nimport { getOrCreateRequest } from '../request-deduplication';\nimport { createLogger } from '../core/logger';\nimport { loadGoogleMapsScript, isGoogleMapsLoaded } from './loadGoogleMapsScript';\nimport type {\n GooglePlaceAutocompletePrediction,\n ParsedAddress,\n AutocompleteOptions,\n} from './types';\n\nconst log = createLogger('google-places');\n\n// Google Maps types are defined in loadGoogleMapsScript.ts\n\n/**\n * Fetch place autocomplete predictions using Google Maps JavaScript API\n *\n * @param query - Search query string\n * @param apiKey - Google Places API key\n * @param options - Optional autocomplete options\n * @returns Promise resolving to array of predictions\n *\n * @example\n * ```ts\n * const predictions = await fetchPlaceAutocomplete(\n * '123 Main St',\n * 'your-api-key',\n * { components: 'country:au' }\n * );\n * ```\n */\nexport async function fetchPlaceAutocomplete(\n query: string,\n apiKey: string,\n options?: AutocompleteOptions\n): Promise<GooglePlaceAutocompletePrediction[]> {\n if (!query.trim()) {\n return [];\n }\n\n if (!apiKey) {\n throw new Error('Google Places API key is required');\n }\n\n // Ensure Google Maps script is loaded\n if (!isGoogleMapsLoaded()) {\n await loadGoogleMapsScript(apiKey, 'places');\n }\n\n const requestKey = `google-places-autocomplete:${query}:${JSON.stringify(options || {})}`;\n\n return getOrCreateRequest(requestKey, async () => {\n try {\n log.debug(`Fetching autocomplete for query: ${query}`);\n\n if (!window.google?.maps?.places) {\n throw new Error('Google Maps Places library not available');\n }\n\n // Try to use the new AutocompleteSuggestion API first, fallback to legacy AutocompleteService\n const useNewAPI = window.google.maps.places.AutocompleteSuggestion !== undefined;\n \n if (useNewAPI) {\n // Use new AutocompleteSuggestion API\n const request: {\n input: string;\n includedRegionCodes?: string[];\n locationBias?: {\n circle?: {\n center: { latitude: number; longitude: number };\n radius: number;\n };\n };\n includedPrimaryTypes?: string[];\n languageCode?: string;\n } = {\n input: query.trim(),\n };\n\n // Parse components option (e.g., \"country:au\" -> [\"au\"])\n if (options?.components) {\n const componentParts = options.components.split('|');\n const countries: string[] = [];\n\n componentParts.forEach((part) => {\n const [key, value] = part.split(':');\n if (key === 'country') {\n countries.push(...value.split(',').map(c => c.toUpperCase()));\n }\n });\n\n if (countries.length > 0) {\n request.includedRegionCodes = countries;\n }\n }\n\n if (options?.location && options?.radius) {\n const [lat, lng] = options.location.split(',').map(Number);\n request.locationBias = {\n circle: {\n center: { latitude: lat, longitude: lng },\n radius: options.radius,\n },\n };\n }\n\n if (options?.language) {\n request.languageCode = options.language;\n }\n\n // Call new API\n return new Promise<GooglePlaceAutocompletePrediction[]>((resolve, reject) => {\n window.google!.maps.places.AutocompleteSuggestion.fetchAutocompleteSuggestions(request)\n .then((response) => {\n if (response.suggestions && response.suggestions.length > 0) {\n const result: GooglePlaceAutocompletePrediction[] = response.suggestions\n .filter(s => s.placePrediction)\n .map((s) => ({\n description: s.placePrediction!.text.text,\n place_id: s.placePrediction!.placeId,\n structured_formatting: {\n main_text: s.placePrediction!.structuredFormat?.mainText?.text || s.placePrediction!.text.text,\n secondary_text: s.placePrediction!.structuredFormat?.secondaryText?.text || '',\n },\n }));\n log.debug(`Received ${result.length} predictions (new API)`);\n resolve(result);\n } else {\n log.debug('No results found (new API)');\n resolve([]);\n }\n })\n .catch((error) => {\n log.error('Autocomplete fetch failed (new API):', error);\n reject(new Error(`Failed to fetch autocomplete predictions: ${error.message || 'Unknown error'}`));\n });\n });\n }\n\n // Fallback to legacy AutocompleteService\n const autocompleteService = new window.google.maps.places.AutocompleteService();\n\n // Build request\n const request: {\n input: string;\n componentRestrictions?: { country: string | string[] };\n location?: { lat: () => number; lng: () => number };\n radius?: number;\n types?: string[];\n language?: string;\n } = {\n input: query.trim(),\n };\n\n // Parse components option (e.g., \"country:au\" -> { country: \"AU\" })\n if (options?.components) {\n const componentParts = options.components.split('|');\n const restrictions: { country?: string[] } = {};\n const countries: string[] = [];\n\n componentParts.forEach((part) => {\n const [key, value] = part.split(':');\n if (key === 'country') {\n // Convert to uppercase for consistency with Google Maps API\n countries.push(...value.split(',').map(c => c.toUpperCase()));\n }\n });\n\n if (countries.length > 0) {\n request.componentRestrictions = { country: countries.length === 1 ? countries[0] : countries };\n }\n }\n\n if (options?.location) {\n const [lat, lng] = options.location.split(',').map(Number);\n if (window.google?.maps?.LatLng) {\n request.location = new window.google.maps.LatLng(lat, lng);\n }\n }\n\n if (options?.radius) {\n request.radius = options.radius;\n }\n\n if (options?.types) {\n request.types = [options.types];\n }\n\n if (options?.language) {\n request.language = options.language;\n }\n\n // Call AutocompleteService\n return new Promise<GooglePlaceAutocompletePrediction[]>((resolve, reject) => {\n autocompleteService.getPlacePredictions(request, (predictions, status) => {\n if (status === 'OK' && predictions) {\n log.debug(`Received ${predictions.length} predictions`);\n // Convert to our format\n const result: GooglePlaceAutocompletePrediction[] = predictions.map((pred) => ({\n description: pred.description,\n place_id: pred.place_id,\n structured_formatting: {\n main_text: pred.structured_formatting.main_text,\n secondary_text: pred.structured_formatting.secondary_text,\n },\n }));\n resolve(result);\n } else if (status === 'ZERO_RESULTS') {\n log.debug('No results found');\n resolve([]);\n } else {\n const errorMsg = `Google Places API error: ${status}`;\n log.error('Autocomplete fetch failed:', errorMsg);\n reject(new Error(errorMsg));\n }\n });\n });\n } catch (error) {\n if (error instanceof Error) {\n log.error('Autocomplete fetch failed:', error.message);\n throw error;\n }\n log.error('Autocomplete fetch failed: Unknown error');\n throw new Error('Failed to fetch autocomplete predictions');\n }\n });\n}\n\n/**\n * Fetch place details from Google Places API\n *\n * @param placeId - Google Place ID\n * @param apiKey - Google Places API key\n * @returns Promise resolving to place details\n *\n * @example\n * ```ts\n * const place = await fetchPlaceDetails('ChIJ...', 'your-api-key');\n * ```\n */\nexport async function fetchPlaceDetails(\n placeId: string,\n apiKey: string\n): Promise<{\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n}> {\n if (!placeId) {\n throw new Error('Place ID is required');\n }\n\n if (!apiKey) {\n throw new Error('Google Places API key is required');\n }\n\n // Ensure Google Maps script is loaded\n if (!isGoogleMapsLoaded()) {\n await loadGoogleMapsScript(apiKey, 'places');\n }\n\n const requestKey = `google-places-details:${placeId}`;\n\n return getOrCreateRequest(requestKey, async () => {\n try {\n log.debug(`Fetching place details for place_id: ${placeId}`);\n\n if (!window.google?.maps?.places) {\n throw new Error('Google Maps Places library not available');\n }\n\n // Create a dummy element for PlacesService (it needs an element but we don't use it)\n const dummyElement = document.createElement('div');\n const placesService = new window.google.maps.places.PlacesService(dummyElement);\n\n // Call getDetails\n return new Promise<{\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n }>((resolve, reject) => {\n placesService.getDetails(\n {\n placeId: placeId,\n fields: ['place_id', 'formatted_address', 'address_components', 'geometry'],\n },\n (place, status) => {\n if (status === 'OK' && place) {\n log.debug('Place details fetched successfully');\n resolve(place as any);\n } else if (status === 'NOT_FOUND') {\n log.error('Place not found:', placeId);\n reject(new Error('Place not found'));\n } else {\n const errorMsg = `Failed to fetch place details: ${status}`;\n log.error('Place details fetch failed:', errorMsg);\n reject(new Error(errorMsg));\n }\n }\n );\n });\n } catch (error) {\n if (error instanceof Error) {\n log.error('Place details fetch failed:', error.message);\n throw error;\n }\n log.error('Place details fetch failed: Unknown error');\n throw new Error('Failed to fetch place details');\n }\n });\n}\n\n/**\n * Parse address components from Google Places API response\n *\n * @param components - Array of address components from Google API\n * @returns Parsed address components\n */\nexport function parseAddressComponents(\n components: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }> | undefined\n): {\n street_number: string | null;\n route: string | null;\n suburb: string | null;\n state: string | null;\n postcode: string | null;\n country: string | null;\n} {\n if (!components || components.length === 0) {\n return {\n street_number: null,\n route: null,\n suburb: null,\n state: null,\n postcode: null,\n country: null,\n };\n }\n\n const result = {\n street_number: null as string | null,\n route: null as string | null,\n suburb: null as string | null,\n state: null as string | null,\n postcode: null as string | null,\n country: null as string | null,\n };\n\n for (const component of components) {\n const types = component.types || [];\n\n if (types.includes('street_number')) {\n result.street_number = component.long_name;\n } else if (types.includes('route')) {\n result.route = component.long_name;\n } else if (types.includes('locality') || types.includes('sublocality')) {\n result.suburb = component.long_name;\n } else if (types.includes('administrative_area_level_1')) {\n result.state = component.short_name;\n } else if (types.includes('postal_code')) {\n result.postcode = component.long_name;\n } else if (types.includes('country')) {\n result.country = component.short_name;\n }\n }\n\n return result;\n}\n\n/**\n * Create parsed address from Google Places API place result\n *\n * @param place - Place result from Google Places Details API\n * @returns Parsed address matching pace_address table structure\n */\nexport function createAddressFromPlaceResult(\n place: {\n place_id: string;\n formatted_address?: string;\n address_components?: Array<{\n long_name: string;\n short_name: string;\n types: string[];\n }>;\n geometry?: {\n location?: {\n lat: () => number;\n lng: () => number;\n };\n };\n }\n): ParsedAddress {\n const components = parseAddressComponents(place.address_components || []);\n\n return {\n place_id: place.place_id,\n full_address: place.formatted_address || null,\n street_number: components.street_number,\n route: components.route,\n suburb: components.suburb,\n state: components.state,\n postcode: components.postcode,\n country: components.country,\n lat: place.geometry?.location?.lat() ?? null,\n lng: place.geometry?.location?.lng() ?? null,\n };\n}\n\n/**\n * Get full address details by place_id\n * Useful for retrieving address from stored place_id without autocomplete search\n *\n * @param placeId - Google Place ID\n * @param apiKey - Google Places API key\n * @returns Promise resolving to parsed address\n *\n * @example\n * ```ts\n * const address = await getAddressByPlaceId('ChIJ...', 'your-api-key');\n * // Returns: { place_id: 'ChIJ...', full_address: '...', ... }\n * ```\n */\nexport async function getAddressByPlaceId(\n placeId: string,\n apiKey: string\n): Promise<ParsedAddress | null> {\n try {\n const place = await fetchPlaceDetails(placeId, apiKey);\n return createAddressFromPlaceResult(place);\n } catch (error) {\n log.error('Failed to get address by place_id:', error);\n return null;\n }\n}\n\n","\ninterface PerformanceBudget {\n metric: string;\n budget: number;\n actual: number;\n threshold: 'error' | 'warning' | 'info';\n}\n\ninterface PerformanceMetrics {\n bundleSize: number;\n chunkCount: number;\n treeshakingEffectiveness: number;\n dynamicImportUsage: number;\n}\n\ninterface MeasurementResult {\n passed: boolean;\n value: number;\n threshold: number;\n}\n\n// Performance budget thresholds with index signature\nexport const PERFORMANCE_BUDGETS: { [key: string]: { threshold: number } } = {\n COMPONENT_RENDER: { threshold: 50 },\n BUNDLE_SIZE: { threshold: 150000 },\n CHUNK_COUNT: { threshold: 10 },\n TREESHAKING_SCORE: { threshold: 70 },\n ERROR_BOUNDARY_TRIGGER: { threshold: 5 },\n MEMORY_INCREASE: { threshold: 1000 },\n LARGE_LIST_RENDER: { threshold: 500 },\n} as const;\n\nclass PerformanceBudgetMonitor {\n private metrics: Map<string, number> = new Map();\n private budgets: PerformanceBudget[] = [];\n\n measure(metric: string, value: number, metadata?: Record<string, unknown>): MeasurementResult {\n this.metrics.set(metric, value);\n \n // In production, this would send to a proper logging service\n // For now, we'll log to console for testing purposes\n if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test' || process.env.NODE_ENV === 'test') {\n console.log('📊 Performance Metric: ' + metric + ' = ' + value, metadata);\n }\n\n // Get threshold for this metric\n const budgetConfig = PERFORMANCE_BUDGETS[metric];\n const threshold = budgetConfig?.threshold || 100;\n const passed = value <= threshold;\n\n return {\n passed,\n value,\n threshold\n };\n }\n\n setBudget(metric: string, budget: number, threshold: 'error' | 'warning' | 'info' = 'warning'): void {\n this.budgets.push({ metric, budget, actual: 0, threshold });\n }\n\n checkBudgets(): PerformanceBudget[] {\n const violations: PerformanceBudget[] = [];\n \n for (const budget of this.budgets) {\n const actual = this.metrics.get(budget.metric) || 0;\n budget.actual = actual;\n \n if (actual > budget.budget) {\n violations.push(budget);\n \n // In production, this would send to a proper logging service\n // For now, we'll log to console for testing purposes\n if (import.meta.env.MODE === 'development' || import.meta.env.MODE === 'test' || process.env.NODE_ENV === 'test') {\n if (budget.threshold === 'error') {\n console.error('❌ Performance budget exceeded: ' + budget.metric + ' (' + actual + ' > ' + budget.budget + ')');\n } else if (budget.threshold === 'warning') {\n console.warn('⚠️ Performance budget exceeded: ' + budget.metric + ' (' + actual + ' > ' + budget.budget + ')');\n } else {\n console.info('ℹ️ Performance budget exceeded: ' + budget.metric + ' (' + actual + ' > ' + budget.budget + ')');\n }\n }\n }\n }\n \n return violations;\n }\n\n getMetrics(): PerformanceMetrics {\n return {\n bundleSize: this.metrics.get('BUNDLE_SIZE') || 0,\n chunkCount: this.metrics.get('CHUNK_COUNT') || 0,\n treeshakingEffectiveness: this.metrics.get('TREESHAKING_SCORE') || 0,\n dynamicImportUsage: this.metrics.get('DYNAMIC_IMPORTS') || 0,\n };\n }\n\n reset(): void {\n this.metrics.clear();\n this.budgets.length = 0;\n }\n}\n\nexport const performanceBudgetMonitor = new PerformanceBudgetMonitor();\n\n// Set default performance budgets\nperformanceBudgetMonitor.setBudget('BUNDLE_SIZE', 150000, 'error'); // 150KB\nperformanceBudgetMonitor.setBudget('CHUNK_COUNT', 10, 'warning');\nperformanceBudgetMonitor.setBudget('TREESHAKING_SCORE', 70, 'warning');\nperformanceBudgetMonitor.setBudget('ERROR_BOUNDARY_TRIGGER', 5, 'error');\n"],"mappings":"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","names":["log","request"]}