@jmruthers/pace-core 0.6.10 → 0.6.12

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 (1500) hide show
  1. package/CHANGELOG.md +21 -0
  2. package/audit-tool/00-dependencies.cjs +46 -13
  3. package/audit-tool/audits/01-pace-core-compliance.cjs +96 -21
  4. package/audit-tool/audits/02-project-structure.cjs +13 -3
  5. package/audit-tool/audits/03-architecture.cjs +78 -4
  6. package/audit-tool/audits/04-code-quality.cjs +9 -2
  7. package/audit-tool/audits/05-styling.cjs +19 -7
  8. package/audit-tool/audits/06-security-rbac.cjs +105 -14
  9. package/audit-tool/audits/07-api-tech-stack.cjs +31 -15
  10. package/audit-tool/audits/08-testing-documentation.cjs +11 -3
  11. package/audit-tool/audits/09-operations.cjs +19 -7
  12. package/audit-tool/index.cjs +22 -11
  13. package/audit-tool/utils/report-utils.cjs +4 -0
  14. package/cursor-rules/01-pace-core-compliance.mdc +1 -0
  15. package/cursor-rules/02-project-structure.mdc +1 -0
  16. package/cursor-rules/03-architecture.mdc +3 -1
  17. package/cursor-rules/04-code-quality.mdc +1 -0
  18. package/cursor-rules/05-styling.mdc +41 -7
  19. package/cursor-rules/06-security-rbac.mdc +2 -1
  20. package/cursor-rules/07-api-tech-stack.mdc +1 -0
  21. package/cursor-rules/08-testing-documentation.mdc +1 -0
  22. package/cursor-rules/09-operations.mdc +1 -0
  23. package/dist/DataTable-AQAHSFLM.js +17 -0
  24. package/dist/InactivityServiceProvider-BbxwwDz1.d.ts +308 -0
  25. package/dist/UnifiedAuthProvider-Bkt_tzdS.d.ts +183 -0
  26. package/dist/api-6OQXYT67.js +6 -0
  27. package/dist/api-result-USV1Czr-.d.ts +51 -0
  28. package/dist/audit-HI2DHUVU.js +4 -0
  29. package/dist/auth-JvdRVaud.d.ts +49 -0
  30. package/dist/chunk-2DL2WSOE.js +327 -0
  31. package/dist/chunk-2GBDPPUC.js +61 -0
  32. package/dist/chunk-44CNXN4P.js +15 -0
  33. package/dist/chunk-AP5FG7W4.js +2159 -0
  34. package/dist/chunk-CU2BU2MQ.js +2 -0
  35. package/dist/chunk-D6BMFMQZ.js +200 -0
  36. package/dist/chunk-ENLXB7GP.js +721 -0
  37. package/dist/chunk-GHCUP64P.js +105 -0
  38. package/dist/chunk-H6RTU4DZ.js +1098 -0
  39. package/dist/chunk-HQTYP6BX.js +6468 -0
  40. package/dist/chunk-M7QE7XOA.js +529 -0
  41. package/dist/chunk-MVVWZ7JV.js +1329 -0
  42. package/dist/chunk-NJ7FGQWB.js +811 -0
  43. package/dist/chunk-QRYSEPHB.js +429 -0
  44. package/dist/chunk-QWIG36BZ.js +264 -0
  45. package/dist/chunk-S57OLCLO.js +2946 -0
  46. package/dist/chunk-VFLR5K2H.js +23 -0
  47. package/dist/chunk-XOJME5T7.js +407 -0
  48. package/dist/chunk-XPFVT3GN.js +492 -0
  49. package/dist/chunk-Y2LWSLLB.js +9614 -0
  50. package/dist/chunk-YFGNMB67.js +2390 -0
  51. package/dist/components.d.ts +10 -9
  52. package/dist/components.js +20 -17
  53. package/dist/database.generated-qkdoiVrJ.d.ts +9441 -0
  54. package/dist/eslint-rules/index.cjs +3 -0
  55. package/dist/eslint-rules/rules/03-architecture.cjs +74 -0
  56. package/dist/eslint-rules/rules/06-security-rbac.cjs +74 -0
  57. package/dist/event-BfCox3N2.d.ts +265 -0
  58. package/dist/file-reference-DU1hcawx.d.ts +164 -0
  59. package/dist/functions-hF5ImHCr.d.ts +208 -0
  60. package/dist/hooks.d.ts +22 -9
  61. package/dist/hooks.js +35 -25
  62. package/dist/icons/index.d.ts +1 -0
  63. package/dist/icons/index.js +1 -0
  64. package/dist/index.d.ts +69 -180
  65. package/dist/index.js +319 -342
  66. package/dist/pagination-BW1mqywp.d.ts +201 -0
  67. package/dist/providers.d.ts +6 -5
  68. package/dist/providers.js +6 -3
  69. package/dist/rbac/index.d.ts +133 -148
  70. package/dist/rbac/index.js +12 -9
  71. package/dist/theming/runtime.d.ts +19 -2
  72. package/dist/theming/runtime.js +1 -1
  73. package/dist/timezone-BTWWXKVY.d.ts +696 -0
  74. package/dist/types-Besvoyzb.d.ts +55 -0
  75. package/dist/types-CGHrxfqc.d.ts +114 -0
  76. package/dist/types.d.ts +19 -12
  77. package/dist/types.js +1 -0
  78. package/dist/usePublicPageContext-BQrHf95t.d.ts +4367 -0
  79. package/dist/usePublicRouteParams-BgV6VhMi.d.ts +946 -0
  80. package/dist/utils.d.ts +163 -145
  81. package/dist/utils.js +45 -27
  82. package/docs/api/@jmruthers/namespaces/DialogPortal/README.md +14 -0
  83. package/docs/api/@jmruthers/namespaces/DialogPortal/variables/displayName.md +11 -0
  84. package/docs/api/README.md +6 -2
  85. package/docs/api/_media/README.md +186 -0
  86. package/docs/api/classes/ColumnFactory.md +225 -0
  87. package/docs/api/classes/Logger.md +246 -0
  88. package/docs/api/classes/RBACAuditManager.md +299 -0
  89. package/docs/api/classes/RBACCache.md +389 -0
  90. package/docs/api/classes/RBACEngine.md +181 -0
  91. package/docs/api/classes/SecureSupabaseClient.md +168 -0
  92. package/docs/api/classes/StorageUtils.md +324 -0
  93. package/docs/api/enumerations/FileCategory.md +137 -0
  94. package/docs/api/enumerations/LogLevel.md +43 -0
  95. package/docs/api/enumerations/RBACErrorCode.md +169 -0
  96. package/docs/api/enumerations/RPCFunction.md +89 -0
  97. package/docs/api/functions/AccessDenied.md +30 -0
  98. package/docs/api/functions/AppSwitcher.md +21 -0
  99. package/docs/api/functions/Badge.md +42 -0
  100. package/docs/api/functions/ContextSelector.md +43 -0
  101. package/docs/api/functions/DataTable.md +36 -0
  102. package/docs/api/functions/DatePickerWithTimezone.md +28 -0
  103. package/docs/api/functions/DialogBody.md +24 -0
  104. package/docs/api/functions/DialogFooter.md +24 -0
  105. package/docs/api/functions/DialogHeader.md +24 -0
  106. package/docs/api/functions/ErrorBoundaryProvider.md +28 -0
  107. package/docs/api/functions/EventServiceProvider.md +28 -0
  108. package/docs/api/functions/FileDisplay.md +25 -0
  109. package/docs/api/functions/FileUpload.md +21 -0
  110. package/docs/api/functions/Form.md +50 -0
  111. package/docs/api/functions/FormField.md +102 -0
  112. package/docs/api/functions/Header.md +21 -0
  113. package/docs/api/functions/InactivityServiceProvider.md +28 -0
  114. package/docs/api/functions/InactivityWarningModal.md +21 -0
  115. package/docs/api/functions/Input.md +49 -0
  116. package/docs/api/functions/NavigationGuard.md +31 -0
  117. package/docs/api/functions/OrganisationServiceProvider.md +28 -0
  118. package/docs/api/functions/PaceAppLayout.md +169 -0
  119. package/docs/api/functions/PasswordChangeForm.md +21 -0
  120. package/docs/api/functions/ProtectedRoute.md +37 -0
  121. package/docs/api/functions/PublicPageFooter.md +21 -0
  122. package/docs/api/functions/PublicPageHeader.md +21 -0
  123. package/docs/api/functions/PublicPageLayout.md +33 -0
  124. package/docs/api/functions/PublicPageProvider.md +30 -0
  125. package/docs/api/functions/Textarea.md +49 -0
  126. package/docs/api/functions/Toaster.md +34 -0
  127. package/docs/api/functions/UnifiedAuthProvider.md +28 -0
  128. package/docs/api/functions/applyPalette.md +33 -0
  129. package/docs/api/functions/archiveFile.md +47 -0
  130. package/docs/api/functions/average.md +63 -0
  131. package/docs/api/functions/buildAppUrl.md +46 -0
  132. package/docs/api/functions/clearInFlightRequests.md +17 -0
  133. package/docs/api/functions/clearPalette.md +18 -0
  134. package/docs/api/functions/clearPublicEventCache.md +18 -0
  135. package/docs/api/functions/clearPublicFileDisplayCache.md +18 -0
  136. package/docs/api/functions/clearPublicLogoCache.md +18 -0
  137. package/docs/api/functions/cn.md +21 -0
  138. package/docs/api/functions/count.md +56 -0
  139. package/docs/api/functions/createAuditManager.md +45 -0
  140. package/docs/api/functions/createBaseClient.md +75 -0
  141. package/docs/api/functions/createLogger.md +95 -0
  142. package/docs/api/functions/createRBACConfig.md +21 -0
  143. package/docs/api/functions/createRBACEngine.md +33 -0
  144. package/docs/api/functions/createRBACExpressMiddleware.md +84 -0
  145. package/docs/api/functions/createRBACMiddleware.md +88 -0
  146. package/docs/api/functions/createSecureClient.md +80 -0
  147. package/docs/api/functions/createSecureDataAccess.md +39 -0
  148. package/docs/api/functions/deleteFile.md +33 -0
  149. package/docs/api/functions/disablePerformanceMonitoring.md +17 -0
  150. package/docs/api/functions/downloadFile.md +33 -0
  151. package/docs/api/functions/emitAuditEvent.md +27 -0
  152. package/docs/api/functions/enablePerformanceMonitoring.md +17 -0
  153. package/docs/api/functions/err.md +23 -0
  154. package/docs/api/functions/exportToCSV.md +56 -0
  155. package/docs/api/functions/exportToCSVWithTableRows.md +46 -0
  156. package/docs/api/functions/extractEventCodeFromPath.md +24 -0
  157. package/docs/api/functions/extractFileMetadata.md +33 -0
  158. package/docs/api/functions/formatCompactNumber.md +27 -0
  159. package/docs/api/functions/formatCurrency.md +31 -0
  160. package/docs/api/functions/formatDate.md +23 -0
  161. package/docs/api/functions/formatDateTime.md +24 -0
  162. package/docs/api/functions/formatFileSize.md +23 -0
  163. package/docs/api/functions/formatInTimeZone.md +46 -0
  164. package/docs/api/functions/formatNumber.md +31 -0
  165. package/docs/api/functions/formatPercent.md +64 -0
  166. package/docs/api/functions/formatTime.md +24 -0
  167. package/docs/api/functions/formatTimeInTimeZone.md +40 -0
  168. package/docs/api/functions/fromSupabaseClient.md +49 -0
  169. package/docs/api/functions/fromZonedTime.md +41 -0
  170. package/docs/api/functions/generateCSVContent.md +55 -0
  171. package/docs/api/functions/generateFilePath.md +29 -0
  172. package/docs/api/functions/generateFileUrlsBatch.md +33 -0
  173. package/docs/api/functions/generatePublicRoutePath.md +27 -0
  174. package/docs/api/functions/generateUniqueFileName.md +24 -0
  175. package/docs/api/functions/getAccessLevel.md +48 -0
  176. package/docs/api/functions/getAllAppPorts.md +19 -0
  177. package/docs/api/functions/getAllStylePaths.md +15 -0
  178. package/docs/api/functions/getAppConfig.md +17 -0
  179. package/docs/api/functions/getAppPort.md +34 -0
  180. package/docs/api/functions/getBucketName.md +27 -0
  181. package/docs/api/functions/getCurrentAppId.md +17 -0
  182. package/docs/api/functions/getCurrentAppName.md +17 -0
  183. package/docs/api/functions/getFileSizeLimit.md +23 -0
  184. package/docs/api/functions/getGlobalAuditManager.md +19 -0
  185. package/docs/api/functions/getInFlightRequestCount.md +19 -0
  186. package/docs/api/functions/getPerformanceMetrics.md +17 -0
  187. package/docs/api/functions/getPerformanceSummary.md +17 -0
  188. package/docs/api/functions/getPermissionMap.md +52 -0
  189. package/docs/api/functions/getPublicEventCacheStats.md +25 -0
  190. package/docs/api/functions/getPublicFileDisplayCacheStats.md +25 -0
  191. package/docs/api/functions/getPublicLogoCacheStats.md +25 -0
  192. package/docs/api/functions/getPublicUrl.md +39 -0
  193. package/docs/api/functions/getRBACConfig.md +15 -0
  194. package/docs/api/functions/getRBACLogger.md +15 -0
  195. package/docs/api/functions/getRoleContext.md +31 -0
  196. package/docs/api/functions/getSignedUrl.md +34 -0
  197. package/docs/api/functions/getStylePath.md +21 -0
  198. package/docs/api/functions/getTimeZoneDifference.md +40 -0
  199. package/docs/api/functions/getTimezoneAbbreviation.md +40 -0
  200. package/docs/api/functions/getUserTimeZone.md +26 -0
  201. package/docs/api/functions/hasAllPermissions.md +41 -0
  202. package/docs/api/functions/hasAnyPermission.md +41 -0
  203. package/docs/api/functions/isDebugMode.md +15 -0
  204. package/docs/api/functions/isDevelopmentMode.md +15 -0
  205. package/docs/api/functions/isErr.md +29 -0
  206. package/docs/api/functions/isOk.md +29 -0
  207. package/docs/api/functions/isPerformanceMonitoringEnabled.md +17 -0
  208. package/docs/api/functions/isPermitted.md +58 -0
  209. package/docs/api/functions/isPermittedCached.md +36 -0
  210. package/docs/api/functions/isRBACInitialized.md +19 -0
  211. package/docs/api/functions/isSecureClient.md +38 -0
  212. package/docs/api/functions/isValidPermission.md +27 -0
  213. package/docs/api/functions/listFiles.md +29 -0
  214. package/docs/api/functions/max.md +63 -0
  215. package/docs/api/functions/min.md +63 -0
  216. package/docs/api/functions/ok.md +29 -0
  217. package/docs/api/functions/parseAndNormalizeEventColours.md +105 -0
  218. package/docs/api/functions/recordAuditEvent.md +23 -0
  219. package/docs/api/functions/recordPermissionCheck.md +31 -0
  220. package/docs/api/functions/resetPerformanceMetrics.md +17 -0
  221. package/docs/api/functions/resolveAppContext.md +27 -0
  222. package/docs/api/functions/roundToNearestMinutes.md +41 -0
  223. package/docs/api/functions/sanitizeFormData.md +49 -0
  224. package/docs/api/functions/sanitizeHtml.md +39 -0
  225. package/docs/api/functions/sanitizeUserInput.md +27 -0
  226. package/docs/api/functions/setAppConfig.md +23 -0
  227. package/docs/api/functions/setGlobalAuditManager.md +25 -0
  228. package/docs/api/functions/setupRBAC.md +31 -0
  229. package/docs/api/functions/sum.md +63 -0
  230. package/docs/api/functions/toZonedTime.md +41 -0
  231. package/docs/api/functions/uploadFile.md +32 -0
  232. package/docs/api/functions/useAccessLevel.md +71 -0
  233. package/docs/api/functions/useAccessibleApps.md +55 -0
  234. package/docs/api/functions/useAppConfig.md +20 -0
  235. package/docs/api/functions/useAuthService.md +15 -0
  236. package/docs/api/functions/useCan.md +99 -0
  237. package/docs/api/functions/useEventService.md +15 -0
  238. package/docs/api/functions/useEventTheme.md +26 -0
  239. package/docs/api/functions/useEvents.md +45 -0
  240. package/docs/api/functions/useFileReference.md +264 -0
  241. package/docs/api/functions/useFileReferenceById.md +63 -0
  242. package/docs/api/functions/useFileReferenceForRecord.md +129 -0
  243. package/docs/api/functions/useFilesByCategory.md +80 -0
  244. package/docs/api/functions/useFormDialog.md +62 -0
  245. package/docs/api/functions/useInactivityService.md +15 -0
  246. package/docs/api/functions/useInactivityTracker.md +21 -0
  247. package/docs/api/functions/useIsPublicPage.md +19 -0
  248. package/docs/api/functions/useMultiplePermissions.md +88 -0
  249. package/docs/api/functions/useOptionalEvents.md +31 -0
  250. package/docs/api/functions/useOrganisationPermissions.md +27 -0
  251. package/docs/api/functions/useOrganisationSecurity.md +15 -0
  252. package/docs/api/functions/useOrganisationService.md +15 -0
  253. package/docs/api/functions/useOrganisations.md +48 -0
  254. package/docs/api/functions/usePermissions.md +130 -0
  255. package/docs/api/functions/usePublicEvent.md +36 -0
  256. package/docs/api/functions/usePublicEventCode.md +32 -0
  257. package/docs/api/functions/usePublicEventLogo.md +48 -0
  258. package/docs/api/functions/usePublicFileDisplay.md +54 -0
  259. package/docs/api/functions/usePublicPageContext.md +19 -0
  260. package/docs/api/functions/usePublicRouteParams.md +31 -0
  261. package/docs/api/functions/useRBAC.md +21 -0
  262. package/docs/api/functions/useResolvedScope.md +46 -0
  263. package/docs/api/functions/useResourcePermissions.md +25 -0
  264. package/docs/api/functions/useRoleManagement.md +121 -0
  265. package/docs/api/functions/useSecureSupabase.md +51 -0
  266. package/docs/api/functions/useSessionRestoration.md +15 -0
  267. package/docs/api/functions/useSessionTracking.md +62 -0
  268. package/docs/api/functions/useToast.md +83 -0
  269. package/docs/api/functions/useUnifiedAuth.md +24 -0
  270. package/docs/api/functions/useZodForm.md +27 -0
  271. package/docs/api/functions/validateFileSize.md +31 -0
  272. package/docs/api/functions/warnIfInsecureClient.md +40 -0
  273. package/docs/api/functions/withAccessLevelGuard.md +67 -0
  274. package/docs/api/functions/withPermissionGuard.md +73 -0
  275. package/docs/api/functions/withRoleGuard.md +86 -0
  276. package/docs/api/globals.md +502 -0
  277. package/docs/api/interfaces/AccessDeniedProps.md +87 -0
  278. package/docs/api/interfaces/AccessibleApp.md +41 -0
  279. package/docs/api/interfaces/AddressFieldProps.md +195 -0
  280. package/docs/api/interfaces/AddressFieldRef.md +67 -0
  281. package/docs/api/interfaces/AggregateConfig.md +35 -0
  282. package/docs/api/interfaces/AppSwitcherProps.md +51 -0
  283. package/docs/api/interfaces/AuthSessionData.md +27 -0
  284. package/docs/api/interfaces/AutocompleteOptions.md +61 -0
  285. package/docs/api/interfaces/AvatarProps.md +97 -0
  286. package/docs/api/interfaces/BadgeProps.md +30 -0
  287. package/docs/api/interfaces/BuildAppUrlOptions.md +41 -0
  288. package/docs/api/interfaces/ButtonProps.md +46 -0
  289. package/docs/api/interfaces/CalendarProps.md +60 -0
  290. package/docs/api/interfaces/CardProps.md +56 -0
  291. package/docs/api/interfaces/ColorPalette.md +13 -0
  292. package/docs/api/interfaces/ColorShade.md +58 -0
  293. package/docs/api/interfaces/ContextSelectorProps.md +131 -0
  294. package/docs/api/interfaces/DataRecord.md +16 -0
  295. package/docs/api/interfaces/DataTableAction.md +198 -0
  296. package/docs/api/interfaces/DataTableColumn.md +422 -0
  297. package/docs/api/interfaces/DataTableProps.md +511 -0
  298. package/docs/api/interfaces/DataTableToolbarButton.md +75 -0
  299. package/docs/api/interfaces/DatePickerWithTimezoneProps.md +75 -0
  300. package/docs/api/interfaces/DialogBodyProps.md +55 -0
  301. package/docs/api/interfaces/DialogCloseProps.md +25 -0
  302. package/docs/api/interfaces/DialogContentProps.md +160 -0
  303. package/docs/api/interfaces/DialogFooterProps.md +25 -0
  304. package/docs/api/interfaces/DialogHeaderProps.md +25 -0
  305. package/docs/api/interfaces/DialogPortalProps.md +19 -0
  306. package/docs/api/interfaces/DialogProps.md +53 -0
  307. package/docs/api/interfaces/DialogTriggerProps.md +53 -0
  308. package/docs/api/interfaces/EmptyStateConfig.md +55 -0
  309. package/docs/api/interfaces/ErrorBoundaryProps.md +131 -0
  310. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +31 -0
  311. package/docs/api/interfaces/ErrorBoundaryState.md +61 -0
  312. package/docs/api/interfaces/EventAppRoleData.md +54 -0
  313. package/docs/api/interfaces/ExportColumn.md +69 -0
  314. package/docs/api/interfaces/ExportOptions.md +109 -0
  315. package/docs/api/interfaces/FileDisplayProps.md +192 -0
  316. package/docs/api/interfaces/FileMetadata.md +97 -0
  317. package/docs/api/interfaces/FileReference.md +89 -0
  318. package/docs/api/interfaces/FileSizeLimits.md +13 -0
  319. package/docs/api/interfaces/FileUploadOptions.md +107 -0
  320. package/docs/api/interfaces/FooterProps.md +37 -0
  321. package/docs/api/interfaces/FormFieldProps.md +171 -0
  322. package/docs/api/interfaces/FormProps.md +93 -0
  323. package/docs/api/interfaces/GrantEventAppRoleParams.md +97 -0
  324. package/docs/api/interfaces/ImportSummary.md +49 -0
  325. package/docs/api/interfaces/InactivityWarningModalProps.md +87 -0
  326. package/docs/api/interfaces/InputProps.md +46 -0
  327. package/docs/api/interfaces/InvalidScopeError.md +37 -0
  328. package/docs/api/interfaces/LabelProps.md +85 -0
  329. package/docs/api/interfaces/LoggerConfig.md +51 -0
  330. package/docs/api/interfaces/LoginFormProps.md +146 -0
  331. package/docs/api/interfaces/MissingUserContextError.md +37 -0
  332. package/docs/api/interfaces/NavigationGuardProps.md +109 -0
  333. package/docs/api/interfaces/NavigationItem.md +91 -0
  334. package/docs/api/interfaces/NavigationMenuProps.md +169 -0
  335. package/docs/api/interfaces/Organisation.md +105 -0
  336. package/docs/api/interfaces/OrganisationContextRequiredError.md +37 -0
  337. package/docs/api/interfaces/OrganisationMembership.md +105 -0
  338. package/docs/api/interfaces/OrganisationSecurityError.md +49 -0
  339. package/docs/api/interfaces/PaceAppLayoutPermissionConfig.md +127 -0
  340. package/docs/api/interfaces/PaceAppLayoutRouteConfigItem.md +91 -0
  341. package/docs/api/interfaces/PaceAppLayoutRoutingConfig.md +79 -0
  342. package/docs/api/interfaces/PaceLoginPageProps.md +41 -0
  343. package/docs/api/interfaces/PagePermissionGuardProps.md +143 -0
  344. package/docs/api/interfaces/PaletteData.md +33 -0
  345. package/docs/api/interfaces/ParsedAddress.md +91 -0
  346. package/docs/api/interfaces/PermissionDeniedError.md +37 -0
  347. package/docs/api/interfaces/ProgressProps.md +35 -0
  348. package/docs/api/interfaces/ProtectedRouteProps.md +67 -0
  349. package/docs/api/interfaces/PublicPageFooterProps.md +97 -0
  350. package/docs/api/interfaces/PublicPageHeaderProps.md +99 -0
  351. package/docs/api/interfaces/PublicPageLayoutProps.md +153 -0
  352. package/docs/api/interfaces/RBACAccessValidateParams.md +41 -0
  353. package/docs/api/interfaces/RBACAccessValidateResult.md +33 -0
  354. package/docs/api/interfaces/RBACAuditLogParams.md +65 -0
  355. package/docs/api/interfaces/RBACAuditLogResult.md +41 -0
  356. package/docs/api/interfaces/RBACContext.md +41 -0
  357. package/docs/api/interfaces/RBACError.md +37 -0
  358. package/docs/api/interfaces/RBACLogger.md +97 -0
  359. package/docs/api/interfaces/RBACNotInitializedError.md +37 -0
  360. package/docs/api/interfaces/RBACPageAccessCheckParams.md +57 -0
  361. package/docs/api/interfaces/RBACPerformanceMetrics.md +109 -0
  362. package/docs/api/interfaces/RBACPermissionCheckParams.md +57 -0
  363. package/docs/api/interfaces/RBACPermissionCheckResult.md +41 -0
  364. package/docs/api/interfaces/RBACPermissionsGetParams.md +49 -0
  365. package/docs/api/interfaces/RBACPermissionsGetResult.md +49 -0
  366. package/docs/api/interfaces/RBACResult.md +47 -0
  367. package/docs/api/interfaces/RBACRoleGrantParams.md +49 -0
  368. package/docs/api/interfaces/RBACRoleGrantResult.md +41 -0
  369. package/docs/api/interfaces/RBACRoleRevokeParams.md +49 -0
  370. package/docs/api/interfaces/RBACRoleRevokeResult.md +41 -0
  371. package/docs/api/interfaces/RBACRoleValidateParams.md +41 -0
  372. package/docs/api/interfaces/RBACRoleValidateResult.md +49 -0
  373. package/docs/api/interfaces/RBACRolesListParams.md +41 -0
  374. package/docs/api/interfaces/RBACRolesListResult.md +57 -0
  375. package/docs/api/interfaces/RBACSessionTrackParams.md +57 -0
  376. package/docs/api/interfaces/RBACSessionTrackResult.md +41 -0
  377. package/docs/api/interfaces/ResourcePermissions.md +119 -0
  378. package/docs/api/interfaces/RevokeEventAppRoleParams.md +81 -0
  379. package/docs/api/interfaces/RoleManagementResult.md +41 -0
  380. package/docs/api/interfaces/SessionRestorationLoaderProps.md +29 -0
  381. package/docs/api/interfaces/StorageConfig.md +33 -0
  382. package/docs/api/interfaces/StorageFileInfo.md +57 -0
  383. package/docs/api/interfaces/StorageFileMetadata.md +113 -0
  384. package/docs/api/interfaces/StorageListOptions.md +79 -0
  385. package/docs/api/interfaces/StorageListResult.md +33 -0
  386. package/docs/api/interfaces/StorageUploadOptions.md +81 -0
  387. package/docs/api/interfaces/StorageUploadResult.md +49 -0
  388. package/docs/api/interfaces/StorageUploadSuccess.md +35 -0
  389. package/docs/api/interfaces/StorageUrlOptions.md +49 -0
  390. package/docs/api/interfaces/StyleImport.md +17 -0
  391. package/docs/api/interfaces/SwitchProps.md +30 -0
  392. package/docs/api/interfaces/TabsContentProps.md +13 -0
  393. package/docs/api/interfaces/TabsListProps.md +13 -0
  394. package/docs/api/interfaces/TabsProps.md +13 -0
  395. package/docs/api/interfaces/TabsTriggerProps.md +41 -0
  396. package/docs/api/interfaces/TextareaProps.md +43 -0
  397. package/docs/api/interfaces/ToastActionElement.md +16 -0
  398. package/docs/api/interfaces/ToastProps.md +13 -0
  399. package/docs/api/interfaces/UnifiedAuthProviderProps.md +129 -0
  400. package/docs/api/interfaces/UseAccessibleAppsReturn.md +55 -0
  401. package/docs/api/interfaces/UseFormDialogOptions.md +49 -0
  402. package/docs/api/interfaces/UseFormDialogReturn.md +95 -0
  403. package/docs/api/interfaces/UseInactivityTrackerOptions.md +103 -0
  404. package/docs/api/interfaces/UseInactivityTrackerReturn.md +91 -0
  405. package/docs/api/interfaces/UsePublicEventLogoOptions.md +69 -0
  406. package/docs/api/interfaces/UsePublicEventLogoReturn.md +66 -0
  407. package/docs/api/interfaces/UsePublicEventOptions.md +29 -0
  408. package/docs/api/interfaces/UsePublicEventReturn.md +56 -0
  409. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +39 -0
  410. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +96 -0
  411. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +76 -0
  412. package/docs/api/interfaces/UseResolvedScopeOptions.md +49 -0
  413. package/docs/api/interfaces/UseResolvedScopeReturn.md +39 -0
  414. package/docs/api/interfaces/UseResourcePermissionsOptions.md +29 -0
  415. package/docs/api/interfaces/UserEventAccess.md +92 -0
  416. package/docs/api/interfaces/UserMenuProps.md +69 -0
  417. package/docs/api/interfaces/UserProfile.md +49 -0
  418. package/docs/api/type-aliases/AccessLevel.md +11 -0
  419. package/docs/api/type-aliases/AccessLevelContext.md +14 -0
  420. package/docs/api/type-aliases/AllPermissions.md +11 -0
  421. package/docs/api/type-aliases/ApiError.md +37 -0
  422. package/docs/api/type-aliases/ApiResult.md +19 -0
  423. package/docs/api/type-aliases/AuditEventType.md +11 -0
  424. package/docs/api/type-aliases/BadgeVariant.md +18 -0
  425. package/docs/api/type-aliases/DataTableFeatureConfig.md +14 -0
  426. package/docs/api/type-aliases/DialogSize.md +13 -0
  427. package/docs/api/type-aliases/EventAppRole.md +11 -0
  428. package/docs/api/type-aliases/FileUploadProps.md +15 -0
  429. package/docs/api/type-aliases/GetRowId.md +33 -0
  430. package/docs/api/type-aliases/GlobalErrorHandler.md +35 -0
  431. package/docs/api/type-aliases/GlobalRole.md +11 -0
  432. package/docs/api/type-aliases/ImportHandlerResult.md +13 -0
  433. package/docs/api/type-aliases/NavigationMode.md +13 -0
  434. package/docs/api/type-aliases/Operation.md +11 -0
  435. package/docs/api/type-aliases/OrganisationContextType.md +13 -0
  436. package/docs/api/type-aliases/OrganisationRole.md +11 -0
  437. package/docs/api/type-aliases/PaceAppLayoutProps.md +14 -0
  438. package/docs/api/type-aliases/Permission.md +11 -0
  439. package/docs/api/type-aliases/PermissionCheck.md +46 -0
  440. package/docs/api/type-aliases/PermissionMap.md +11 -0
  441. package/docs/api/type-aliases/PermissionSource.md +13 -0
  442. package/docs/api/type-aliases/RBACConfig.md +13 -0
  443. package/docs/api/type-aliases/RBACFunctionResponse.md +57 -0
  444. package/docs/api/type-aliases/Scope.md +41 -0
  445. package/docs/api/type-aliases/SessionType.md +11 -0
  446. package/docs/api/type-aliases/UUID.md +11 -0
  447. package/docs/api/type-aliases/UnifiedAuthContextType.md +13 -0
  448. package/docs/api/type-aliases/UseFileReferenceForRecordReturn.md +161 -0
  449. package/docs/api/type-aliases/UseFileReferenceOptions.md +35 -0
  450. package/docs/api/type-aliases/UseFileReferenceReturn.md +13 -0
  451. package/docs/api/variables/ALL_PERMISSIONS.md +281 -0
  452. package/docs/api/variables/APP_PATH_MAPPING.md +14 -0
  453. package/docs/api/variables/AddressField.md +41 -0
  454. package/docs/api/variables/Alert.md +11 -0
  455. package/docs/api/variables/AlertDescription.md +11 -0
  456. package/docs/api/variables/AlertTitle.md +11 -0
  457. package/docs/api/variables/Avatar.md +13 -0
  458. package/docs/api/variables/Button.md +31 -0
  459. package/docs/api/variables/CACHE_PATTERNS.md +89 -0
  460. package/docs/api/variables/Calendar.md +74 -0
  461. package/docs/api/variables/Card.md +11 -0
  462. package/docs/api/variables/CardActions.md +11 -0
  463. package/docs/api/variables/CardContent.md +11 -0
  464. package/docs/api/variables/CardDescription.md +11 -0
  465. package/docs/api/variables/CardFooter.md +11 -0
  466. package/docs/api/variables/CardHeader.md +11 -0
  467. package/docs/api/variables/CardTitle.md +11 -0
  468. package/docs/api/variables/Checkbox.md +11 -0
  469. package/docs/api/variables/DEFAULT_APP_PORT_MAP.md +14 -0
  470. package/docs/api/variables/DEFAULT_FILE_SIZE_LIMIT.md +13 -0
  471. package/docs/api/variables/Dialog.md +14 -0
  472. package/docs/api/variables/DialogClose.md +14 -0
  473. package/docs/api/variables/DialogContent.md +28 -0
  474. package/docs/api/variables/DialogDescription.md +14 -0
  475. package/docs/api/variables/DialogPortal.md +14 -0
  476. package/docs/api/variables/DialogTitle.md +14 -0
  477. package/docs/api/variables/DialogTrigger.md +14 -0
  478. package/docs/api/variables/EVENT_APP_PERMISSIONS.md +109 -0
  479. package/docs/api/variables/ErrorBoundary.md +15 -0
  480. package/docs/api/variables/FILE_SIZE_LIMITS.md +13 -0
  481. package/docs/api/variables/Footer.md +11 -0
  482. package/docs/api/variables/GLOBAL_PERMISSIONS.md +29 -0
  483. package/docs/api/variables/Label.md +34 -0
  484. package/docs/api/variables/LoadingSpinner.md +28 -0
  485. package/docs/api/variables/LoginForm.md +34 -0
  486. package/docs/api/variables/NavigationMenu.md +203 -0
  487. package/docs/api/variables/ORGANISATION_PERMISSIONS.md +89 -0
  488. package/docs/api/variables/PAGE_PERMISSIONS.md +93 -0
  489. package/docs/api/variables/PaceLoginPage.md +40 -0
  490. package/docs/api/variables/PagePermissionGuard.md +11 -0
  491. package/docs/api/variables/Progress.md +32 -0
  492. package/docs/api/variables/SECURE_CLIENT_SYMBOL.md +14 -0
  493. package/docs/api/variables/STORAGE_CONFIG.md +13 -0
  494. package/docs/api/variables/Select.md +26 -0
  495. package/docs/api/variables/SelectContent.md +26 -0
  496. package/docs/api/variables/SelectGroup.md +26 -0
  497. package/docs/api/variables/SelectItem.md +26 -0
  498. package/docs/api/variables/SelectLabel.md +26 -0
  499. package/docs/api/variables/SelectSeparator.md +26 -0
  500. package/docs/api/variables/SelectTrigger.md +26 -0
  501. package/docs/api/variables/SelectValue.md +26 -0
  502. package/docs/api/variables/SessionRestorationLoader.md +11 -0
  503. package/docs/api/variables/Switch.md +23 -0
  504. package/docs/api/variables/Table.md +35 -0
  505. package/docs/api/variables/TableBody.md +11 -0
  506. package/docs/api/variables/TableCaption.md +11 -0
  507. package/docs/api/variables/TableCell.md +11 -0
  508. package/docs/api/variables/TableFooter.md +11 -0
  509. package/docs/api/variables/TableHead.md +11 -0
  510. package/docs/api/variables/TableHeader.md +11 -0
  511. package/docs/api/variables/TableRow.md +11 -0
  512. package/docs/api/variables/Tabs.md +25 -0
  513. package/docs/api/variables/TabsContent.md +24 -0
  514. package/docs/api/variables/TabsList.md +25 -0
  515. package/docs/api/variables/TabsTrigger.md +34 -0
  516. package/docs/api/variables/Toast.md +36 -0
  517. package/docs/api/variables/ToastAction.md +32 -0
  518. package/docs/api/variables/ToastClose.md +32 -0
  519. package/docs/api/variables/ToastDescription.md +32 -0
  520. package/docs/api/variables/ToastProvider.md +11 -0
  521. package/docs/api/variables/ToastTitle.md +32 -0
  522. package/docs/api/variables/ToastViewport.md +26 -0
  523. package/docs/api/variables/Tooltip.md +34 -0
  524. package/docs/api/variables/TooltipContent.md +34 -0
  525. package/docs/api/variables/TooltipProvider.md +11 -0
  526. package/docs/api/variables/TooltipRoot.md +11 -0
  527. package/docs/api/variables/TooltipTrigger.md +11 -0
  528. package/docs/api/variables/UserMenu.md +11 -0
  529. package/docs/api/variables/emailSchema.md +13 -0
  530. package/docs/api/variables/logger.md +203 -0
  531. package/docs/api/variables/nameSchema.md +13 -0
  532. package/docs/api/variables/passwordSchema.md +13 -0
  533. package/docs/api/variables/phoneSchema.md +13 -0
  534. package/docs/api/variables/rbacCache.md +16 -0
  535. package/docs/api/variables/styleConfig.md +25 -0
  536. package/docs/api/variables/urlSchema.md +13 -0
  537. package/docs/api-reference/hooks.md +2 -0
  538. package/docs/api-reference/rpc-functions.md +12 -3
  539. package/docs/core-concepts/rbac-system.md +8 -0
  540. package/docs/getting-started/cursor-rules.md +17 -20
  541. package/docs/getting-started/dependencies.md +1 -1
  542. package/docs/getting-started/setup.md +235 -0
  543. package/docs/implementation-guides/authentication.md +27 -0
  544. package/docs/implementation-guides/data-tables.md +184 -3
  545. package/docs/migration/ApiResult-migration.md +25 -0
  546. package/docs/rbac/api-reference.md +33 -31
  547. package/docs/rbac/getting-started.md +7 -0
  548. package/docs/rbac/troubleshooting.md +5 -1
  549. package/docs/standards/0-standards-overview.md +50 -15
  550. package/docs/standards/1-pace-core-compliance-standards.md +62 -57
  551. package/docs/standards/2-project-structure-standards.md +33 -16
  552. package/docs/standards/3-architecture-standards.md +41 -1
  553. package/docs/standards/4-code-quality-standards.md +26 -6
  554. package/docs/standards/5-styling-standards.md +35 -1
  555. package/docs/standards/6-security-rbac-standards.md +66 -0
  556. package/docs/standards/7-api-tech-stack-standards.md +25 -14
  557. package/docs/standards/8-testing-documentation-standards.md +31 -0
  558. package/docs/standards/9-operations-standards.md +19 -0
  559. package/docs/standards/README.md +20 -201
  560. package/docs/testing/test-setup-for-consumers.md +2 -0
  561. package/docs/troubleshooting/common-issues.md +17 -1
  562. package/docs/troubleshooting/organisation-context-setup.md +8 -0
  563. package/docs/troubleshooting/print-event-name-css-variable-analysis.md +217 -0
  564. package/eslint-config-pace-core.cjs +20 -0
  565. package/package.json +16 -22
  566. package/scripts/build-docs.js +180 -0
  567. package/scripts/setup.cjs +536 -0
  568. package/scripts/validate.cjs +480 -0
  569. package/src/__tests__/helpers/component-test-utils.test.tsx +260 -0
  570. package/src/__tests__/helpers/optimized-test-setup.test.ts +224 -0
  571. package/src/__tests__/helpers/supabaseMock.test.ts +273 -0
  572. package/src/__tests__/helpers/test-providers.test.tsx +99 -0
  573. package/src/__tests__/helpers/test-providers.tsx +37 -39
  574. package/src/__tests__/helpers/test-utils.test.tsx +447 -0
  575. package/src/__tests__/helpers/timer-utils.test.ts +371 -0
  576. package/src/assets/app-icons/index.test.ts +304 -0
  577. package/src/components/AddressField/AddressField.test.tsx +1 -1
  578. package/src/components/AddressField/AddressField.tsx +238 -212
  579. package/src/components/Button/Button.tsx +1 -1
  580. package/src/components/Card/Card.test.tsx +172 -17
  581. package/src/components/Card/Card.tsx +19 -10
  582. package/src/components/ContextSelector/ContextSelector.internals.tsx +204 -0
  583. package/src/components/ContextSelector/ContextSelector.test.tsx +360 -0
  584. package/src/components/ContextSelector/ContextSelector.tsx +66 -280
  585. package/src/components/ContextSelector/ContextSelector.types.ts +35 -0
  586. package/src/components/ContextSelector/useContextSelectorState.tsx +195 -0
  587. package/src/components/DataTable/AUDIT_REPORT.md +59 -44
  588. package/src/components/DataTable/DataTable.comprehensive.test.tsx +759 -0
  589. package/src/components/DataTable/DataTable.default-state.test.tsx +524 -0
  590. package/src/components/DataTable/DataTable.export.test.tsx +705 -0
  591. package/src/components/DataTable/DataTable.grouping-aggregation.test.tsx +658 -0
  592. package/src/components/DataTable/DataTable.hooks.test.tsx +192 -0
  593. package/src/components/DataTable/DataTable.select-label-display.test.tsx +485 -0
  594. package/src/components/DataTable/DataTable.test.tsx +787 -416
  595. package/src/components/DataTable/DataTable.tsx +12 -12
  596. package/src/components/DataTable/DataTableCore.integration.test.tsx +458 -0
  597. package/src/components/DataTable/DataTableCore.test-setup.ts +221 -0
  598. package/src/components/DataTable/DataTableCore.test.tsx +970 -0
  599. package/src/components/DataTable/README.md +155 -0
  600. package/src/components/DataTable/TESTING.md +101 -0
  601. package/src/components/DataTable/a11y.basic.test.tsx +788 -0
  602. package/src/components/DataTable/components/DataTableCore.tsx +104 -864
  603. package/src/components/DataTable/components/GroupingDropdown.test.tsx +621 -0
  604. package/src/components/DataTable/components/GroupingDropdown.tsx +2 -2
  605. package/src/components/DataTable/components/ImportModal.tsx +61 -559
  606. package/src/components/DataTable/components/ImportModalFileSection.tsx +148 -0
  607. package/src/components/DataTable/context/DataTableContext.test.tsx +328 -0
  608. package/src/components/DataTable/context/DataTableContext.tsx +7 -6
  609. package/src/components/DataTable/core/ColumnFactory.test.ts +403 -0
  610. package/src/components/DataTable/hooks/useColumnOrderPersistence.test.ts +516 -0
  611. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.test.ts +256 -0
  612. package/src/components/DataTable/hooks/useDataTableConfiguration.test.ts +297 -0
  613. package/src/components/DataTable/hooks/useDataTableConfiguration.ts +14 -2
  614. package/src/components/DataTable/hooks/useDataTableDataPipeline.test.ts +270 -0
  615. package/src/components/DataTable/hooks/useDataTableDeletionBatching.test.ts +127 -0
  616. package/src/components/DataTable/hooks/useDataTableDeletionBatching.ts +106 -0
  617. package/src/components/DataTable/hooks/useDataTableEffectiveActions.test.ts +461 -0
  618. package/src/components/DataTable/hooks/useDataTableEffectiveActions.ts +248 -0
  619. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.test.ts +296 -0
  620. package/src/components/DataTable/hooks/useDataTableLayoutHandlers.ts +175 -0
  621. package/src/components/DataTable/hooks/useDataTablePaginationSync.test.ts +203 -0
  622. package/src/components/DataTable/hooks/useDataTablePaginationSync.ts +109 -0
  623. package/src/components/DataTable/hooks/useDataTablePermissions.test.ts +280 -0
  624. package/src/components/DataTable/hooks/useDataTablePermissions.ts +79 -247
  625. package/src/components/DataTable/hooks/useDataTablePipeline.test.tsx +219 -0
  626. package/src/components/DataTable/hooks/useDataTablePipeline.tsx +239 -0
  627. package/src/components/DataTable/hooks/useDataTableRenderGuard.test.tsx +316 -0
  628. package/src/components/DataTable/hooks/useDataTableRenderGuard.tsx +195 -0
  629. package/src/components/DataTable/hooks/useDataTableScope.test.ts +102 -0
  630. package/src/components/DataTable/hooks/useDataTableScope.ts +125 -0
  631. package/src/components/DataTable/hooks/useDataTableState.test.ts +733 -0
  632. package/src/components/DataTable/hooks/useDataTableState.ts +145 -94
  633. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.test.ts +277 -0
  634. package/src/components/DataTable/hooks/useDataTableStateAndPersistence.ts +222 -0
  635. package/src/components/DataTable/hooks/useDataTableSuperAdmin.test.ts +93 -0
  636. package/src/components/DataTable/hooks/useDataTableSuperAdmin.ts +86 -0
  637. package/src/components/DataTable/hooks/useDataTableTableInstance.test.ts +185 -0
  638. package/src/components/DataTable/hooks/useDataTableTableInstance.ts +178 -0
  639. package/src/components/DataTable/hooks/useEffectiveColumnOrder.test.ts +183 -0
  640. package/src/components/DataTable/hooks/useHierarchicalState.test.ts +294 -0
  641. package/src/components/DataTable/hooks/useImportModalFocus.test.ts +184 -0
  642. package/src/components/DataTable/hooks/useImportModalFocus.ts +53 -0
  643. package/src/components/DataTable/hooks/useImportModalState.test.ts +390 -0
  644. package/src/components/DataTable/hooks/useImportModalState.ts +345 -0
  645. package/src/components/DataTable/hooks/useKeyboardNavigation.test.ts +787 -0
  646. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +309 -269
  647. package/src/components/DataTable/hooks/usePermissionTracking.test.ts +381 -0
  648. package/src/components/DataTable/hooks/usePermissionTracking.ts +122 -0
  649. package/src/components/DataTable/hooks/useServerSideDataEffect.test.ts +258 -0
  650. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +14 -3
  651. package/src/components/DataTable/hooks/useTableColumns.test.ts +499 -0
  652. package/src/components/DataTable/hooks/useTableHandlers.test.ts +461 -0
  653. package/src/components/DataTable/hooks/useTableHandlers.ts +5 -2
  654. package/src/components/DataTable/index.ts +18 -17
  655. package/src/components/DataTable/keyboard.test.tsx +734 -0
  656. package/src/components/DataTable/mocks/MockRBACProvider.tsx +66 -0
  657. package/src/components/DataTable/pagination.modes.test.tsx +728 -0
  658. package/src/components/DataTable/ssr.strict-mode.test.tsx +319 -0
  659. package/src/components/DataTable/styles.test.ts +379 -0
  660. package/src/components/DataTable/styles.ts +0 -1
  661. package/src/components/DataTable/test-utils/MockDataTableComponents.tsx +55 -0
  662. package/src/components/DataTable/test-utils/dataFactories.ts +103 -0
  663. package/src/components/DataTable/test-utils/featureConfig.ts +10 -0
  664. package/src/components/DataTable/test-utils/sharedTestUtils.ts +419 -0
  665. package/src/components/DataTable/test-utils.ts +94 -0
  666. package/src/components/DataTable/types/actions.ts +71 -0
  667. package/src/components/DataTable/types/base.ts +39 -0
  668. package/src/components/DataTable/types/columns.ts +125 -0
  669. package/src/components/DataTable/types/export.ts +32 -0
  670. package/src/components/DataTable/types/features.ts +81 -0
  671. package/src/components/DataTable/types/hierarchical.ts +44 -0
  672. package/src/components/DataTable/types/index.ts +43 -0
  673. package/src/components/DataTable/types/pagination.ts +85 -0
  674. package/src/components/DataTable/types/performance.ts +47 -0
  675. package/src/components/DataTable/types/props.ts +62 -0
  676. package/src/components/DataTable/types/rbac.ts +45 -0
  677. package/src/components/DataTable/ui/layout/DataTableCore.test.tsx +1194 -0
  678. package/src/components/DataTable/ui/layout/DataTableCore.tsx +345 -0
  679. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.test.tsx +438 -0
  680. package/src/components/DataTable/ui/layout/DataTableErrorBoundary.tsx +225 -0
  681. package/src/components/DataTable/ui/layout/DataTableLayout.test.tsx +1352 -0
  682. package/src/components/DataTable/ui/layout/DataTableLayout.tsx +661 -0
  683. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.test.tsx +91 -0
  684. package/src/components/DataTable/ui/modals/BulkDeleteConfirmDialog.tsx +43 -0
  685. package/src/components/DataTable/ui/modals/DataTableModals.test.tsx +749 -0
  686. package/src/components/DataTable/ui/modals/DataTableModals.tsx +341 -0
  687. package/src/components/DataTable/ui/modals/ImportModal.test.tsx +1834 -0
  688. package/src/components/DataTable/ui/modals/ImportModal.tsx +197 -0
  689. package/src/components/DataTable/ui/modals/ImportModalFailedRowsSection.tsx +60 -0
  690. package/src/components/DataTable/ui/modals/ImportModalFileSection.tsx +148 -0
  691. package/src/components/DataTable/ui/modals/ImportModalPreviewSection.tsx +60 -0
  692. package/src/components/DataTable/ui/modals/ImportModalSummarySection.tsx +59 -0
  693. package/src/components/DataTable/ui/modals/importModalPersistence.ts +73 -0
  694. package/src/components/DataTable/ui/shared/AccessDeniedPage.test.tsx +245 -0
  695. package/src/components/DataTable/ui/shared/AccessDeniedPage.tsx +159 -0
  696. package/src/components/DataTable/ui/shared/ActionButtons.test.tsx +921 -0
  697. package/src/components/DataTable/ui/shared/ActionButtons.tsx +195 -0
  698. package/src/components/DataTable/ui/shared/ColumnFilter.test.tsx +497 -0
  699. package/src/components/DataTable/ui/shared/ColumnFilter.tsx +113 -0
  700. package/src/components/DataTable/ui/shared/PaginationControls.test.tsx +451 -0
  701. package/src/components/DataTable/ui/shared/PaginationControls.tsx +291 -0
  702. package/src/components/DataTable/ui/shared/SortIndicator.test.tsx +135 -0
  703. package/src/components/DataTable/ui/shared/SortIndicator.tsx +50 -0
  704. package/src/components/DataTable/ui/table/EditFields.test.tsx +526 -0
  705. package/src/components/DataTable/ui/table/EditFields.tsx +355 -0
  706. package/src/components/DataTable/ui/table/EditableRow.test.tsx +1003 -0
  707. package/src/components/DataTable/ui/table/EditableRow.tsx +444 -0
  708. package/src/components/DataTable/ui/table/EmptyState.test.tsx +360 -0
  709. package/src/components/DataTable/ui/table/EmptyState.tsx +74 -0
  710. package/src/components/DataTable/ui/table/FilterRow.test.tsx +416 -0
  711. package/src/components/DataTable/ui/table/FilterRow.tsx +148 -0
  712. package/src/components/DataTable/ui/table/LoadingState.test.tsx +77 -0
  713. package/src/components/DataTable/ui/table/LoadingState.tsx +17 -0
  714. package/src/components/DataTable/ui/table/RowComponent.test.tsx +1024 -0
  715. package/src/components/DataTable/ui/table/RowComponent.tsx +429 -0
  716. package/src/components/DataTable/ui/table/UnifiedTableBody.test.tsx +1273 -0
  717. package/src/components/DataTable/ui/table/UnifiedTableBody.tsx +440 -0
  718. package/src/components/DataTable/ui/table/cellValueUtils.test.ts +453 -0
  719. package/src/components/DataTable/ui/table/cellValueUtils.ts +40 -0
  720. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.test.tsx +551 -0
  721. package/src/components/DataTable/ui/toolbar/BulkOperationsDropdown.tsx +160 -0
  722. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.test.tsx +751 -0
  723. package/src/components/DataTable/ui/toolbar/ColumnVisibilityDropdown.tsx +114 -0
  724. package/src/components/DataTable/ui/toolbar/DataTableToolbar.test.tsx +629 -0
  725. package/src/components/DataTable/ui/toolbar/DataTableToolbar.tsx +271 -0
  726. package/src/components/DataTable/ui/toolbar/GroupingDropdown.test.tsx +621 -0
  727. package/src/components/DataTable/ui/toolbar/GroupingDropdown.tsx +107 -0
  728. package/src/components/DataTable/utils/a11yUtils.test.ts +548 -0
  729. package/src/components/DataTable/utils/aggregationUtils.test.ts +288 -0
  730. package/src/components/DataTable/utils/columnUtils.test.ts +94 -0
  731. package/src/components/DataTable/utils/csvParse.test.ts +74 -0
  732. package/src/components/DataTable/utils/csvParse.ts +65 -0
  733. package/src/components/DataTable/utils/errorHandling.test.ts +209 -0
  734. package/src/components/DataTable/utils/exportUtils.test.ts +954 -0
  735. package/src/components/DataTable/utils/flexibleImport.test.ts +573 -0
  736. package/src/components/DataTable/utils/flexibleImport.ts +3 -186
  737. package/src/components/DataTable/utils/hierarchicalSorting.test.ts +235 -0
  738. package/src/components/DataTable/utils/hierarchicalUtils.test.ts +586 -0
  739. package/src/components/DataTable/utils/importDateParser.test.ts +162 -0
  740. package/src/components/DataTable/utils/importDateParser.ts +114 -0
  741. package/src/components/DataTable/utils/importValueParser.test.ts +138 -0
  742. package/src/components/DataTable/utils/importValueParser.ts +91 -0
  743. package/src/components/DataTable/utils/paginationUtils.test.ts +593 -0
  744. package/src/components/DataTable/utils/paginationUtils.ts +6 -3
  745. package/src/components/DataTable/utils/performanceUtils.test.ts +470 -0
  746. package/src/components/DataTable/utils/rowUtils.test.ts +235 -0
  747. package/src/components/DataTable/utils/selectFieldUtils.test.ts +271 -0
  748. package/src/components/DataTable/utils/selectFieldUtils.ts +97 -60
  749. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  750. package/src/components/DateTimeField/DateTimeField.test.tsx +1 -1
  751. package/src/components/Dialog/Dialog.test-utils.ts +49 -0
  752. package/src/components/Dialog/Dialog.test.tsx +896 -89
  753. package/src/components/Dialog/Dialog.tsx +174 -882
  754. package/src/components/Dialog/dialogLock.test.ts +238 -0
  755. package/src/components/Dialog/dialogLock.ts +98 -0
  756. package/src/components/Dialog/index.ts +2 -0
  757. package/src/components/Dialog/useDialogDimensions.test.ts +163 -0
  758. package/src/components/Dialog/useDialogDimensions.ts +140 -0
  759. package/src/components/Dialog/useDialogLifecycle.test.ts +361 -0
  760. package/src/components/Dialog/useDialogLifecycle.ts +135 -0
  761. package/src/components/Dialog/useDialogPersistence.test.ts +381 -0
  762. package/src/components/Dialog/useDialogPersistence.ts +357 -0
  763. package/src/components/FileDisplay/FileDisplay.test.tsx +40 -40
  764. package/src/components/FileDisplay/FileDisplay.tsx +24 -656
  765. package/src/components/FileDisplay/FileDisplayContent.test.tsx +395 -0
  766. package/src/components/FileDisplay/FileDisplayContent.tsx +242 -0
  767. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.test.tsx +74 -0
  768. package/src/components/FileDisplay/FileDisplayDeleteConfirmDialog.tsx +38 -0
  769. package/src/components/FileDisplay/FileDisplayEmptyView.test.tsx +33 -0
  770. package/src/components/FileDisplay/FileDisplayEmptyView.tsx +33 -0
  771. package/src/components/FileDisplay/FileDisplayErrorView.test.tsx +71 -0
  772. package/src/components/FileDisplay/FileDisplayErrorView.tsx +50 -0
  773. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.test.tsx +22 -0
  774. package/src/components/FileDisplay/FileDisplayLoadingFallbackView.tsx +22 -0
  775. package/src/components/FileDisplay/FileDisplayLoadingView.test.tsx +21 -0
  776. package/src/components/FileDisplay/FileDisplayLoadingView.tsx +23 -0
  777. package/src/components/FileDisplay/FileDisplayMultipleFilesView.test.tsx +101 -0
  778. package/src/components/FileDisplay/FileDisplayMultipleFilesView.tsx +109 -0
  779. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.test.tsx +58 -0
  780. package/src/components/FileDisplay/FileDisplaySingleDocumentLinkView.tsx +48 -0
  781. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.test.tsx +111 -0
  782. package/src/components/FileDisplay/FileDisplaySingleFileWithActionsView.tsx +270 -0
  783. package/src/components/FileDisplay/FileDisplaySingleImageView.test.tsx +78 -0
  784. package/src/components/FileDisplay/FileDisplaySingleImageView.tsx +67 -0
  785. package/src/components/FileDisplay/fallbackUtils.test.ts +50 -0
  786. package/src/components/FileDisplay/fallbackUtils.ts +44 -0
  787. package/src/components/FileDisplay/fetchFileDisplayData.ts +24 -0
  788. package/src/components/FileDisplay/fetchFileDisplayData.unit.test.ts +183 -0
  789. package/src/components/FileDisplay/fileDisplayUtils.test.ts +58 -0
  790. package/src/components/FileDisplay/fileDisplayUtils.ts +24 -0
  791. package/src/components/FileDisplay/useFileDisplay.test.ts +538 -0
  792. package/src/components/FileDisplay/useFileDisplay.ts +515 -0
  793. package/src/components/FileDisplay/useFileDisplay.unit.test.ts +1442 -0
  794. package/src/components/FileDisplay/useFileDisplayData.ts +126 -0
  795. package/src/components/FileDisplay/usePublicFileDisplay.test.ts +729 -0
  796. package/src/components/FileDisplay/usePublicFileDisplay.ts +579 -0
  797. package/src/components/FileUpload/FileUpload.test.tsx +16 -10
  798. package/src/components/FileUpload/FileUpload.tsx +107 -525
  799. package/src/components/FileUpload/FileUploadDropZone.tsx +112 -0
  800. package/src/components/FileUpload/FileUploadProgressItem.tsx +86 -0
  801. package/src/components/FileUpload/FileUploadProgressList.tsx +40 -0
  802. package/src/components/FileUpload/useFileUploadManager.test.ts +308 -0
  803. package/src/components/FileUpload/useFileUploadManager.ts +454 -0
  804. package/src/components/FileUpload/useResolvedAppId.test.ts +102 -0
  805. package/src/components/FileUpload/useResolvedAppId.ts +77 -0
  806. package/src/components/Footer/Footer.test.tsx +6 -292
  807. package/src/components/Footer/Footer.tsx +8 -125
  808. package/src/components/Form/Form.test.tsx +44 -27
  809. package/src/components/Form/Form.tsx +64 -287
  810. package/src/components/Form/useFormPersistence.ts +257 -0
  811. package/src/components/Header/Header.test.tsx +17 -18
  812. package/src/components/Header/Header.tsx +10 -1
  813. package/src/components/Input/Input.tsx +1 -1
  814. package/src/components/Label/Label.test.tsx +1 -1
  815. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +1 -1
  816. package/src/components/NavigationMenu/HierarchicalNavItem.tsx +104 -0
  817. package/src/components/NavigationMenu/NavigationMenu.test.tsx +1029 -26
  818. package/src/components/NavigationMenu/NavigationMenu.tsx +61 -361
  819. package/src/components/NavigationMenu/index.ts +6 -1
  820. package/src/components/NavigationMenu/navigationPermissionHelper.ts +188 -0
  821. package/src/components/NavigationMenu/useNavigationFiltering.test.ts +1949 -0
  822. package/src/components/NavigationMenu/useNavigationFiltering.ts +197 -296
  823. package/src/components/NavigationMenu/useNavigationScope.ts +125 -0
  824. package/src/components/PaceAppLayout/PaceAppLayout.edge-cases.test.tsx +109 -70
  825. package/src/components/PaceAppLayout/PaceAppLayout.integration.test.tsx +3 -3
  826. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +16 -19
  827. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +529 -5
  828. package/src/components/PaceAppLayout/PaceAppLayout.tsx +280 -756
  829. package/src/components/PaceAppLayout/useFilteredNavItems.ts +319 -0
  830. package/src/components/PaceAppLayout/usePaceAppLayoutConfig.ts +163 -0
  831. package/src/components/PaceAppLayout/usePaceAppLayoutGate.tsx +150 -0
  832. package/src/components/PaceAppLayout/usePaceAppLayoutPermissions.ts +162 -0
  833. package/src/components/PaceAppLayout/usePaceAppLayoutScope.ts +81 -0
  834. package/src/components/PaceAppLayout/useRoleBasedRouteAccess.ts +157 -0
  835. package/src/components/PaceAppLayout/useSuperAdminFallback.ts +58 -0
  836. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +31 -25
  837. package/src/components/PaceLoginPage/PaceLoginPage.tsx +31 -122
  838. package/src/components/PaceLoginPage/useLoginAppAccess.ts +153 -0
  839. package/src/components/Progress/Progress.tsx +1 -2
  840. package/src/components/ProtectedRoute/ProtectedRoute.tsx +29 -235
  841. package/src/components/ProtectedRoute/useProtectedRouteState.ts +128 -0
  842. package/src/components/ProtectedRoute/useVisibilityRedirectGrace.ts +89 -0
  843. package/src/components/PublicLayout/PublicLayout.test.tsx +217 -36
  844. package/src/components/PublicLayout/PublicPageLayout.tsx +132 -73
  845. package/src/components/PublicLayout/PublicPageProvider.tsx +5 -1
  846. package/src/components/Select/Select.test.tsx +1 -1
  847. package/src/components/Select/Select.tsx +28 -18
  848. package/src/components/Select/context.test.tsx +56 -0
  849. package/src/components/Select/text.test.tsx +104 -0
  850. package/src/components/Select/text.ts +26 -0
  851. package/src/components/Select/useSelectEvents.test.ts +279 -0
  852. package/src/components/Select/useSelectEvents.ts +87 -0
  853. package/src/components/Select/useSelectSearch.test.tsx +295 -0
  854. package/src/components/Select/useSelectSearch.ts +91 -0
  855. package/src/components/Select/useSelectState.test.ts +268 -0
  856. package/src/components/Select/useSelectState.ts +104 -0
  857. package/src/components/Table/Table.test.tsx +348 -0
  858. package/src/components/Tabs/Tabs.test.tsx +270 -0
  859. package/src/components/Tabs/Tabs.tsx +1 -1
  860. package/src/components/Toast/Toast.test.tsx +420 -0
  861. package/src/components/index.test.ts +346 -0
  862. package/src/constants/performance.test.ts +91 -0
  863. package/src/hooks/ServiceHooks.test.tsx +725 -0
  864. package/src/hooks/hooks.integration.test.tsx +608 -0
  865. package/src/hooks/index.ts +7 -4
  866. package/src/hooks/index.unit.test.ts +220 -0
  867. package/src/hooks/public/usePublicEvent.test.ts +1 -1
  868. package/src/hooks/public/usePublicEventLogo.test.ts +1 -1
  869. package/src/hooks/public/usePublicRouteParams.test.ts +1 -1
  870. package/src/hooks/services/useAuth.ts +9 -7
  871. package/src/hooks/useAddressAutocomplete.test.ts +22 -22
  872. package/src/hooks/useAddressAutocomplete.ts +90 -75
  873. package/src/hooks/useAppConfig.unit.test.ts +720 -0
  874. package/src/hooks/useComponentPerformance.unit.test.tsx +316 -0
  875. package/src/hooks/useDataTablePerformance.ts +100 -120
  876. package/src/hooks/useDataTablePerformance.unit.test.ts +720 -0
  877. package/src/hooks/useDataTableState.test.ts +170 -0
  878. package/src/hooks/useDebounce.unit.test.ts +157 -0
  879. package/src/hooks/useEventTheme.test.ts +4 -1
  880. package/src/hooks/useEventTheme.ts +49 -21
  881. package/src/hooks/useEvents.ts +41 -1
  882. package/src/hooks/useEvents.unit.test.ts +227 -0
  883. package/src/hooks/useFileReference.test.ts +44 -41
  884. package/src/hooks/useFileReference.ts +182 -173
  885. package/src/hooks/useFileUrl.ts +1 -1
  886. package/src/hooks/useFileUrl.unit.test.ts +684 -0
  887. package/src/hooks/useFileUrlCache.test.ts +319 -0
  888. package/src/hooks/useFileUrlCache.ts +1 -1
  889. package/src/hooks/useFocusManagement.unit.test.ts +604 -0
  890. package/src/hooks/useFocusTrap.unit.test.tsx +613 -0
  891. package/src/hooks/useFormDialog.test.ts +307 -0
  892. package/src/hooks/useInactivityTracker.ts +138 -131
  893. package/src/hooks/useInactivityTracker.unit.test.ts +450 -0
  894. package/src/hooks/useIsMobile.unit.test.ts +317 -0
  895. package/src/hooks/useIsPrint.ts +62 -0
  896. package/src/hooks/useIsPrint.unit.test.ts +545 -0
  897. package/src/hooks/useKeyboardShortcuts.unit.test.ts +907 -0
  898. package/src/hooks/useOrganisationPermissions.unit.test.tsx +293 -0
  899. package/src/hooks/useOrganisationSecurity.test.ts +3 -3
  900. package/src/hooks/useOrganisationSecurity.ts +190 -201
  901. package/src/hooks/useOrganisationSecurity.unit.test.tsx +959 -0
  902. package/src/hooks/useOrganisations.unit.test.ts +369 -0
  903. package/src/hooks/usePerformanceMonitor.unit.test.ts +683 -0
  904. package/src/hooks/usePermissionCache.test.ts +505 -0
  905. package/src/hooks/usePermissionCache.ts +276 -271
  906. package/src/hooks/usePreventTabReload.test.ts +307 -0
  907. package/src/hooks/usePublicEvent.simple.test.ts +779 -0
  908. package/src/hooks/usePublicEvent.test.ts +664 -0
  909. package/src/hooks/usePublicEvent.unit.test.ts +638 -0
  910. package/src/hooks/usePublicFileDisplay.test.ts +948 -0
  911. package/src/hooks/usePublicRouteParams.unit.test.ts +442 -0
  912. package/src/hooks/useQueryCache.test.ts +391 -0
  913. package/src/hooks/useQueryCache.ts +0 -2
  914. package/src/hooks/useRBAC.unit.test.ts +253 -0
  915. package/src/hooks/useSessionDraft.test.ts +556 -0
  916. package/src/hooks/useSessionRestoration.unit.test.tsx +381 -0
  917. package/src/hooks/useStorage.ts +21 -16
  918. package/src/hooks/useStorage.unit.test.ts +684 -0
  919. package/src/hooks/useToast.test.ts +413 -0
  920. package/src/hooks/useToast.unit.test.tsx +481 -0
  921. package/src/hooks/useZodForm.unit.test.tsx +191 -0
  922. package/src/icons/index.test.ts +133 -0
  923. package/src/icons/index.ts +2 -0
  924. package/src/index.test.ts +528 -0
  925. package/src/index.ts +15 -7
  926. package/src/providers/AuthProvider.test.tsx +218 -0
  927. package/src/providers/EventProvider.test.tsx +487 -0
  928. package/src/providers/InactivityProvider.test-helper.tsx +40 -0
  929. package/src/providers/InactivityProvider.test.tsx +421 -0
  930. package/src/providers/ProviderLifecycle.test.tsx +308 -0
  931. package/src/providers/UnifiedAuthProvider.test.tsx +503 -0
  932. package/src/providers/index.test.ts +138 -0
  933. package/src/providers/services/AuthServiceProvider.integration.test.tsx +229 -0
  934. package/src/providers/services/AuthServiceProvider.test.tsx +643 -0
  935. package/src/providers/services/EventServiceProvider.test.tsx +844 -0
  936. package/src/providers/services/InactivityServiceProvider.test.tsx +667 -0
  937. package/src/providers/services/OrganisationServiceProvider.test.tsx +445 -0
  938. package/src/providers/services/UnifiedAuthContext.ts +30 -27
  939. package/src/providers/services/UnifiedAuthProvider.advanced.test.tsx +434 -0
  940. package/src/providers/services/UnifiedAuthProvider.appId.test.tsx +408 -0
  941. package/src/providers/services/UnifiedAuthProvider.integration.test.tsx +304 -0
  942. package/src/providers/services/UnifiedAuthProvider.tsx +115 -360
  943. package/src/providers/services/contexts.test.tsx +281 -0
  944. package/src/providers/services/useUnifiedAuth.test.tsx +251 -0
  945. package/src/providers/services/useUnifiedAuthContextValue.ts +279 -0
  946. package/src/providers/useInactivity.test-helper.ts +27 -0
  947. package/src/rbac/README.md +7 -5
  948. package/src/rbac/adapters.comprehensive.test.tsx +429 -0
  949. package/src/rbac/adapters.test.tsx +22 -22
  950. package/src/rbac/adapters.tsx +29 -29
  951. package/src/rbac/api.test.ts +1075 -87
  952. package/src/rbac/api.ts +300 -255
  953. package/src/rbac/audit-batched.test.ts +550 -0
  954. package/src/rbac/audit.ts +4 -1
  955. package/src/rbac/auth-rbac-security.integration.test.tsx +300 -0
  956. package/src/rbac/auth-rbac.e2e.test.tsx +510 -0
  957. package/src/rbac/cache-invalidation.test.ts +715 -0
  958. package/src/rbac/components/AccessDenied.test.tsx +324 -0
  959. package/src/rbac/components/NavigationGuard.test.tsx +1148 -0
  960. package/src/rbac/components/NavigationGuard.tsx +2 -1
  961. package/src/rbac/components/PagePermissionGuard.guard.test.tsx +236 -0
  962. package/src/rbac/components/PagePermissionGuard.performance.test.tsx +252 -0
  963. package/src/rbac/components/PagePermissionGuard.race-condition.test.tsx +243 -0
  964. package/src/rbac/components/PagePermissionGuard.test.tsx +1443 -0
  965. package/src/rbac/components/PagePermissionGuard.tsx +177 -372
  966. package/src/rbac/components/PagePermissionGuard.verification.test.tsx +185 -0
  967. package/src/rbac/config.ts +58 -18
  968. package/src/rbac/engine.comprehensive.test.ts +808 -0
  969. package/src/rbac/engine.test.ts +494 -0
  970. package/src/rbac/engine.ts +23 -1
  971. package/src/rbac/errors.ts +89 -55
  972. package/src/rbac/hooks/permissions/runPermissionCheck.ts +91 -0
  973. package/src/rbac/hooks/permissions/useAccessLevel.test.ts +622 -0
  974. package/src/rbac/hooks/permissions/useAccessLevel.ts +16 -6
  975. package/src/rbac/hooks/permissions/useCan.test.ts +837 -0
  976. package/src/rbac/hooks/permissions/useCan.ts +177 -255
  977. package/src/rbac/hooks/permissions/useMultiplePermissions.test.ts +843 -0
  978. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +24 -11
  979. package/src/rbac/hooks/permissions/usePermissions.test.ts +543 -0
  980. package/src/rbac/hooks/permissions/usePermissions.ts +36 -65
  981. package/src/rbac/hooks/useCan.test.ts +44 -45
  982. package/src/rbac/hooks/usePageAccessLogging.ts +160 -0
  983. package/src/rbac/hooks/usePageGuardScope.ts +119 -0
  984. package/src/rbac/hooks/usePagePermissionCheck.ts +67 -0
  985. package/src/rbac/hooks/usePermissions.integration.test.ts +427 -0
  986. package/src/rbac/hooks/usePermissions.stability.test.ts +268 -0
  987. package/src/rbac/hooks/usePermissions.test.ts +54 -54
  988. package/src/rbac/hooks/useRBAC.test.ts +313 -217
  989. package/src/rbac/hooks/useRBAC.ts +145 -81
  990. package/src/rbac/hooks/useResolvedScope.ts +16 -10
  991. package/src/rbac/hooks/useResourcePermissions.test.ts +73 -83
  992. package/src/rbac/hooks/useResourcePermissions.ts +77 -152
  993. package/src/rbac/hooks/useResourcePermissionsSuperAdmin.ts +67 -0
  994. package/src/rbac/hooks/useRoleManagement.test.ts +27 -112
  995. package/src/rbac/hooks/useRoleManagement.ts +153 -585
  996. package/src/rbac/hooks/useSecureSupabase.test.ts +1179 -0
  997. package/src/rbac/hooks/useSecureSupabase.ts +10 -2
  998. package/src/rbac/hooks/useSuperAdminCheck.ts +80 -0
  999. package/src/rbac/performance.test.ts +451 -0
  1000. package/src/rbac/rbac-core.test.tsx +276 -0
  1001. package/src/rbac/rbac-engine-core-logic.test.ts +387 -0
  1002. package/src/rbac/rbac-engine-simplified.test.ts +252 -0
  1003. package/src/rbac/rbac-functions.test.ts +703 -0
  1004. package/src/rbac/rbac-role-isolation.test.ts +456 -0
  1005. package/src/rbac/request-deduplication.test.ts +14 -9
  1006. package/src/rbac/request-deduplication.ts +5 -4
  1007. package/src/rbac/scenarios.user-role.test.tsx +271 -0
  1008. package/src/rbac/secureClient.test.ts +514 -83
  1009. package/src/rbac/secureClient.ts +8 -2
  1010. package/src/rbac/security.test.ts +323 -0
  1011. package/src/rbac/types/roleManagement.ts +66 -0
  1012. package/src/rbac/types.ts +3 -0
  1013. package/src/rbac/utils/clientSecurity.test.ts +192 -0
  1014. package/src/rbac/utils/contextValidator.test.ts +126 -0
  1015. package/src/rbac/utils/contextValidator.ts +5 -1
  1016. package/src/rbac/utils/deep-equal.test.ts +76 -0
  1017. package/src/rbac/utils/eventContext.test.ts +401 -0
  1018. package/src/rbac/utils/eventContext.ts +37 -33
  1019. package/src/rbac/utils/fetchPermissionMap.ts +13 -0
  1020. package/src/rbac/utils/permissionMapHelpers.ts +34 -0
  1021. package/src/rbac/utils/roleManagementRpc.ts +303 -0
  1022. package/src/services/AuthService.edge-cases.test.ts +746 -0
  1023. package/src/services/AuthService.restoreSession.test.ts +59 -0
  1024. package/src/services/AuthService.test.ts +1362 -0
  1025. package/src/services/AuthService.ts +184 -205
  1026. package/src/services/BaseService.edge-cases.test.ts +506 -0
  1027. package/src/services/BaseService.test.ts +363 -0
  1028. package/src/services/EventService.edge-cases.test.ts +636 -0
  1029. package/src/services/EventService.eventColours.test.ts +64 -0
  1030. package/src/services/EventService.test.ts +1250 -0
  1031. package/src/services/EventService.ts +251 -316
  1032. package/src/services/InactivityService.edge-cases.test.ts +492 -0
  1033. package/src/services/InactivityService.lifecycle.test.ts +406 -0
  1034. package/src/services/InactivityService.test.ts +829 -0
  1035. package/src/services/InactivityService.ts +172 -213
  1036. package/src/services/OrganisationService.edge-cases.test.ts +633 -0
  1037. package/src/services/OrganisationService.pagination.test.ts +409 -0
  1038. package/src/services/OrganisationService.test.ts +1579 -0
  1039. package/src/services/OrganisationService.ts +184 -238
  1040. package/src/services/base/BaseService.test.ts +1 -1
  1041. package/src/services/interfaces/IAuthService.test.ts +184 -0
  1042. package/src/services/interfaces/IAuthService.ts +10 -9
  1043. package/src/services/interfaces/IEventService.test.ts +176 -0
  1044. package/src/services/interfaces/IInactivityService.test.ts +183 -0
  1045. package/src/services/interfaces/IOrganisationService.test.ts +207 -0
  1046. package/src/styles/core.css +243 -12
  1047. package/src/theming/parseEventColours.test.ts +321 -0
  1048. package/src/theming/runtime.test.ts +495 -0
  1049. package/src/theming/runtime.ts +71 -2
  1050. package/src/types/api-result.ts +53 -0
  1051. package/src/types/core.test.ts +397 -0
  1052. package/src/types/database-generated.test.ts +78 -0
  1053. package/src/types/database.generated.ts +45 -10
  1054. package/src/types/event.ts +38 -18
  1055. package/src/types/file-reference.test.ts +351 -0
  1056. package/src/types/file-reference.ts +37 -12
  1057. package/src/types/guards.test.ts +246 -0
  1058. package/src/types/index.test.ts +265 -0
  1059. package/src/types/index.ts +3 -0
  1060. package/src/types/organisation.roles.test.ts +55 -0
  1061. package/src/types/organisation.test.ts +1105 -0
  1062. package/src/types/organisation.ts +15 -15
  1063. package/src/types/supabase.ts +13 -4
  1064. package/src/types/theme.test.ts +830 -0
  1065. package/src/types/type-validation.test.ts +526 -0
  1066. package/src/types/validation.test.ts +729 -0
  1067. package/src/utils/app/appIdResolver.test.ts +98 -71
  1068. package/src/utils/app/appIdResolver.ts +31 -20
  1069. package/src/utils/appConfig.unit.test.ts +55 -0
  1070. package/src/utils/audit.unit.test.ts +69 -0
  1071. package/src/utils/auth-utils.unit.test.ts +69 -0
  1072. package/src/utils/bundleAnalysis.unit.test.ts +326 -0
  1073. package/src/utils/cn.unit.test.ts +34 -0
  1074. package/src/utils/context/organisationContext.test.ts +105 -91
  1075. package/src/utils/context/organisationContext.ts +29 -40
  1076. package/src/utils/core/cn.test.ts +66 -0
  1077. package/src/utils/core/debugLogger.test.ts +113 -0
  1078. package/src/utils/core/logger.test.ts +217 -0
  1079. package/src/utils/core/mergeRefs.ts +24 -0
  1080. package/src/utils/debugLogger.test.ts +417 -0
  1081. package/src/utils/deviceFingerprint.unit.test.ts +818 -0
  1082. package/src/utils/dynamic/createLazyComponent.tsx +9 -1
  1083. package/src/utils/dynamic/dynamicUtils.test.ts +185 -0
  1084. package/src/utils/dynamic/lazyLoad.test.tsx +156 -0
  1085. package/src/utils/dynamicUtils.unit.test.ts +331 -0
  1086. package/src/utils/file-reference/file-reference.test.ts +1249 -0
  1087. package/src/utils/file-reference/index.ts +330 -347
  1088. package/src/utils/formatDate.unit.test.ts +109 -0
  1089. package/src/utils/formatting/formatDateTimeTimezone.test.ts +1 -1
  1090. package/src/utils/formatting/formatNumber.test.ts +1 -1
  1091. package/src/utils/formatting.unit.test.ts +99 -0
  1092. package/src/utils/google-places/googlePlacesUtils.test.ts +70 -48
  1093. package/src/utils/google-places/googlePlacesUtils.ts +67 -99
  1094. package/src/utils/google-places/loadGoogleMapsScript.test.ts +25 -22
  1095. package/src/utils/google-places/loadGoogleMapsScript.ts +138 -117
  1096. package/src/utils/index.unit.test.ts +251 -0
  1097. package/src/utils/lazyLoad.unit.test.tsx +319 -0
  1098. package/src/utils/location/location.test.ts +1 -1
  1099. package/src/utils/logger.unit.test.ts +398 -0
  1100. package/src/utils/organisationContext.unit.test.ts +180 -0
  1101. package/src/utils/performance/bundleAnalysis.test.ts +148 -0
  1102. package/src/utils/performance/performanceBenchmark.test.ts +251 -0
  1103. package/src/utils/performance/performanceBudgets.test.ts +241 -0
  1104. package/src/utils/performanceBenchmark.test.ts +174 -0
  1105. package/src/utils/performanceBudgets.unit.test.ts +288 -0
  1106. package/src/utils/permissionTypes.unit.test.ts +250 -0
  1107. package/src/utils/permissionUtils.unit.test.ts +362 -0
  1108. package/src/utils/permissions/permissionTypes.test.ts +149 -0
  1109. package/src/utils/persistence/keyDerivation.test.ts +306 -0
  1110. package/src/utils/persistence/sensitiveFieldDetection.test.ts +271 -0
  1111. package/src/utils/request-deduplication.test.ts +349 -0
  1112. package/src/utils/sanitization.unit.test.ts +346 -0
  1113. package/src/utils/schemaUtils.unit.test.ts +441 -0
  1114. package/src/utils/secureDataAccess.unit.test.ts +334 -0
  1115. package/src/utils/secureErrors.unit.test.ts +390 -0
  1116. package/src/utils/secureStorage.unit.test.ts +289 -0
  1117. package/src/utils/security/auth-utils.ts +34 -23
  1118. package/src/utils/security/secureDataAccess.ts +241 -281
  1119. package/src/utils/security/secureErrors.test.ts +1 -1
  1120. package/src/utils/security/secureStorage.test.ts +1 -1
  1121. package/src/utils/security/security.test.ts +25 -17
  1122. package/src/utils/security/security.ts +15 -18
  1123. package/src/utils/security/securityMonitor.test.ts +1 -1
  1124. package/src/utils/security.unit.test.ts +155 -0
  1125. package/src/utils/securityMonitor.unit.test.ts +276 -0
  1126. package/src/utils/sessionTracking.unit.test.ts +218 -0
  1127. package/src/utils/storage/config.unit.test.ts +239 -0
  1128. package/src/utils/storage/helpers.test.ts +88 -102
  1129. package/src/utils/storage/helpers.ts +173 -251
  1130. package/src/utils/storage/index.unit.test.ts +68 -0
  1131. package/src/utils/storage/types.ts +7 -0
  1132. package/src/utils/supabase/createBaseClient.test.ts +31 -14
  1133. package/src/utils/timezone/timezone.test.ts +1 -1
  1134. package/src/utils/timezone.test.ts +345 -0
  1135. package/src/utils/validation/common.test.ts +115 -0
  1136. package/src/utils/validation/csrf.test.ts +198 -0
  1137. package/src/utils/validation/csrf.ts +42 -41
  1138. package/src/utils/validation/htmlSanitization.unit.test.ts +618 -0
  1139. package/src/utils/validation/passwordSchema.test.ts +164 -0
  1140. package/src/utils/validation/schema.test.ts +127 -0
  1141. package/src/utils/validation/sqlInjectionProtection.test.ts +165 -0
  1142. package/src/utils/validation/user.test.ts +173 -0
  1143. package/src/utils/validation/validation.test.ts +197 -0
  1144. package/src/utils/validation/validationUtils.test.ts +294 -0
  1145. package/src/utils/validation.unit.test.ts +307 -0
  1146. package/src/utils/validationUtils.unit.test.ts +558 -0
  1147. package/dist/DataTable-SAXFG4XI.js +0 -13
  1148. package/dist/InactivityServiceProvider-DHryoh6K.d.ts +0 -299
  1149. package/dist/UnifiedAuthProvider-BBD2PS3Q.js +0 -7
  1150. package/dist/UnifiedAuthProvider-CiBAl9-s.d.ts +0 -151
  1151. package/dist/api-F47QJ7FX.js +0 -4
  1152. package/dist/audit-Z6ZZBWLU.js +0 -3
  1153. package/dist/auth-BZOJqrdd.d.ts +0 -49
  1154. package/dist/chunk-3GWSPISD.js +0 -61
  1155. package/dist/chunk-66R6RLUZ.js +0 -529
  1156. package/dist/chunk-7YDC7LMU.js +0 -487
  1157. package/dist/chunk-BCTXBU6U.js +0 -704
  1158. package/dist/chunk-FBZ7U3ID.js +0 -2209
  1159. package/dist/chunk-FN52B75D.js +0 -246
  1160. package/dist/chunk-JJEYZ3DX.js +0 -165
  1161. package/dist/chunk-KPYQWGFQ.js +0 -183
  1162. package/dist/chunk-KSNLMI7N.js +0 -481
  1163. package/dist/chunk-KYURMOQM.js +0 -977
  1164. package/dist/chunk-LNHFAF4X.js +0 -2279
  1165. package/dist/chunk-MPY44PWB.js +0 -8510
  1166. package/dist/chunk-NIU6DPQV.js +0 -427
  1167. package/dist/chunk-TFIPNIPE.js +0 -5379
  1168. package/dist/chunk-UZNAFKGW.js +0 -125
  1169. package/dist/chunk-W46INAVW.js +0 -1216
  1170. package/dist/chunk-X5EAU5G7.js +0 -793
  1171. package/dist/chunk-Y4PF6HIM.js +0 -2862
  1172. package/dist/database.generated-DT8JTZiP.d.ts +0 -9406
  1173. package/dist/event-WTAQuGcq.d.ts +0 -239
  1174. package/dist/file-reference-BavO2eQj.d.ts +0 -148
  1175. package/dist/functions-DH45k8ec.d.ts +0 -208
  1176. package/dist/timezone-K-ptz3HO.d.ts +0 -696
  1177. package/dist/types-BE2sEHKd.d.ts +0 -55
  1178. package/dist/types-CvOPXWWZ.d.ts +0 -111
  1179. package/dist/types-D05dCGma.d.ts +0 -521
  1180. package/dist/usePublicPageContext-vxBlEHO9.d.ts +0 -4290
  1181. package/dist/usePublicRouteParams-G3Ks53mk.d.ts +0 -877
  1182. package/docs/api/modules.md +0 -9889
  1183. package/scripts/build-docs-incremental.js +0 -179
  1184. package/scripts/eslint-audit.cjs +0 -222
  1185. package/scripts/generate-docs.js +0 -157
  1186. package/scripts/install-cursor-rules.cjs +0 -255
  1187. package/scripts/install-eslint-config.cjs +0 -349
  1188. package/scripts/setup-build-cache.js +0 -73
  1189. package/scripts/validate-pre-publish.js +0 -145
  1190. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +0 -260
  1191. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +0 -224
  1192. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +0 -273
  1193. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +0 -99
  1194. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +0 -446
  1195. package/src/__tests__/helpers/__tests__/timer-utils.test.ts +0 -371
  1196. package/src/__tests__/hooks/usePermissions.test.ts +0 -268
  1197. package/src/__tests__/index.test.ts +0 -532
  1198. package/src/__tests__/integration/UserProfile.test.tsx +0 -124
  1199. package/src/__tests__/public-recipe-view.test.ts +0 -228
  1200. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +0 -222
  1201. package/src/__tests__/rls-policies.test.ts +0 -472
  1202. package/src/components/ContextSelector/__tests__/ContextSelector.test.tsx +0 -360
  1203. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +0 -759
  1204. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +0 -524
  1205. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +0 -705
  1206. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +0 -658
  1207. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +0 -192
  1208. package/src/components/DataTable/__tests__/DataTable.select-label-display.test.tsx +0 -485
  1209. package/src/components/DataTable/__tests__/DataTable.test.tsx +0 -876
  1210. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +0 -220
  1211. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +0 -970
  1212. package/src/components/DataTable/__tests__/README.md +0 -145
  1213. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +0 -788
  1214. package/src/components/DataTable/__tests__/keyboard.test.tsx +0 -756
  1215. package/src/components/DataTable/__tests__/mocks/MockRBACProvider.tsx +0 -66
  1216. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +0 -728
  1217. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +0 -319
  1218. package/src/components/DataTable/__tests__/styles.test.ts +0 -382
  1219. package/src/components/DataTable/__tests__/test-utils/dataFactories.ts +0 -103
  1220. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +0 -388
  1221. package/src/components/DataTable/__tests__/test-utils.ts +0 -94
  1222. package/src/components/DataTable/components/AccessDeniedPage.tsx +0 -159
  1223. package/src/components/DataTable/components/ActionButtons.tsx +0 -195
  1224. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +0 -160
  1225. package/src/components/DataTable/components/ColumnFilter.tsx +0 -113
  1226. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +0 -114
  1227. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +0 -225
  1228. package/src/components/DataTable/components/DataTableLayout.tsx +0 -584
  1229. package/src/components/DataTable/components/DataTableModals.tsx +0 -333
  1230. package/src/components/DataTable/components/DataTableToolbar.tsx +0 -271
  1231. package/src/components/DataTable/components/EditFields.tsx +0 -286
  1232. package/src/components/DataTable/components/EditableRow.tsx +0 -462
  1233. package/src/components/DataTable/components/EmptyState.tsx +0 -82
  1234. package/src/components/DataTable/components/FilterRow.tsx +0 -148
  1235. package/src/components/DataTable/components/LoadingState.tsx +0 -17
  1236. package/src/components/DataTable/components/PaginationControls.tsx +0 -285
  1237. package/src/components/DataTable/components/RowComponent.tsx +0 -423
  1238. package/src/components/DataTable/components/SortIndicator.tsx +0 -50
  1239. package/src/components/DataTable/components/UnifiedTableBody.tsx +0 -395
  1240. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +0 -245
  1241. package/src/components/DataTable/components/__tests__/ActionButtons.test.tsx +0 -919
  1242. package/src/components/DataTable/components/__tests__/BulkOperationsDropdown.test.tsx +0 -544
  1243. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +0 -484
  1244. package/src/components/DataTable/components/__tests__/ColumnVisibilityDropdown.test.tsx +0 -748
  1245. package/src/components/DataTable/components/__tests__/DataTableCore.test.tsx +0 -792
  1246. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +0 -438
  1247. package/src/components/DataTable/components/__tests__/DataTableLayout.test.tsx +0 -467
  1248. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +0 -358
  1249. package/src/components/DataTable/components/__tests__/DataTableToolbar.test.tsx +0 -629
  1250. package/src/components/DataTable/components/__tests__/EditFields.test.tsx +0 -526
  1251. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +0 -994
  1252. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +0 -420
  1253. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +0 -415
  1254. package/src/components/DataTable/components/__tests__/GroupingDropdown.test.tsx +0 -612
  1255. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +0 -957
  1256. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +0 -81
  1257. package/src/components/DataTable/components/__tests__/PaginationControls.test.tsx +0 -429
  1258. package/src/components/DataTable/components/__tests__/RowComponent.test.tsx +0 -629
  1259. package/src/components/DataTable/components/__tests__/SortIndicator.test.tsx +0 -135
  1260. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +0 -864
  1261. package/src/components/DataTable/components/__tests__/cellValueUtils.test.ts +0 -453
  1262. package/src/components/DataTable/components/cellValueUtils.ts +0 -40
  1263. package/src/components/DataTable/components/hooks/useImportModalFocus.test.ts +0 -184
  1264. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +0 -53
  1265. package/src/components/DataTable/components/hooks/usePermissionTracking.test.ts +0 -381
  1266. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -122
  1267. package/src/components/DataTable/context/__tests__/DataTableContext.test.tsx +0 -328
  1268. package/src/components/DataTable/core/ActionManager.ts +0 -235
  1269. package/src/components/DataTable/core/ColumnManager.ts +0 -204
  1270. package/src/components/DataTable/core/DataManager.ts +0 -190
  1271. package/src/components/DataTable/core/LocalDataAdapter.ts +0 -274
  1272. package/src/components/DataTable/core/PluginRegistry.ts +0 -229
  1273. package/src/components/DataTable/core/StateManager.ts +0 -312
  1274. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +0 -235
  1275. package/src/components/DataTable/core/__tests__/ColumnFactory.test.ts +0 -403
  1276. package/src/components/DataTable/core/__tests__/ColumnManager.test.ts +0 -141
  1277. package/src/components/DataTable/core/__tests__/DataManager.test.ts +0 -178
  1278. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +0 -133
  1279. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +0 -142
  1280. package/src/components/DataTable/core/__tests__/StateManager.test.ts +0 -158
  1281. package/src/components/DataTable/core/interfaces.ts +0 -338
  1282. package/src/components/DataTable/hooks/__tests__/useColumnOrderPersistence.test.ts +0 -516
  1283. package/src/components/DataTable/hooks/__tests__/useColumnVisibilityPersistence.test.ts +0 -256
  1284. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +0 -297
  1285. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +0 -270
  1286. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +0 -280
  1287. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +0 -691
  1288. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +0 -183
  1289. package/src/components/DataTable/hooks/__tests__/useHierarchicalState.test.ts +0 -294
  1290. package/src/components/DataTable/hooks/__tests__/useKeyboardNavigation.test.ts +0 -787
  1291. package/src/components/DataTable/hooks/__tests__/useServerSideDataEffect.test.ts +0 -258
  1292. package/src/components/DataTable/hooks/__tests__/useTableColumns.test.ts +0 -499
  1293. package/src/components/DataTable/hooks/__tests__/useTableHandlers.test.ts +0 -440
  1294. package/src/components/DataTable/types.ts +0 -764
  1295. package/src/components/DataTable/utils/__tests__/a11yUtils.test.ts +0 -548
  1296. package/src/components/DataTable/utils/__tests__/aggregationUtils.test.ts +0 -288
  1297. package/src/components/DataTable/utils/__tests__/columnUtils.test.ts +0 -94
  1298. package/src/components/DataTable/utils/__tests__/errorHandling.test.ts +0 -209
  1299. package/src/components/DataTable/utils/__tests__/exportUtils.test.ts +0 -954
  1300. package/src/components/DataTable/utils/__tests__/flexibleImport.test.ts +0 -573
  1301. package/src/components/DataTable/utils/__tests__/hierarchicalSorting.test.ts +0 -235
  1302. package/src/components/DataTable/utils/__tests__/hierarchicalUtils.test.ts +0 -586
  1303. package/src/components/DataTable/utils/__tests__/paginationUtils.test.ts +0 -593
  1304. package/src/components/DataTable/utils/__tests__/performanceUtils.test.ts +0 -470
  1305. package/src/components/DataTable/utils/__tests__/rowUtils.test.ts +0 -235
  1306. package/src/components/DataTable/utils/__tests__/selectFieldUtils.test.ts +0 -208
  1307. package/src/components/NavigationMenu/__tests__/useNavigationFiltering.test.ts +0 -1934
  1308. package/src/components/Select/__tests__/context.test.tsx +0 -56
  1309. package/src/components/Select/hooks/__tests__/useSelectEvents.test.ts +0 -279
  1310. package/src/components/Select/hooks/__tests__/useSelectSearch.test.tsx +0 -295
  1311. package/src/components/Select/hooks/__tests__/useSelectState.test.ts +0 -254
  1312. package/src/components/Select/hooks/useSelectEvents.ts +0 -87
  1313. package/src/components/Select/hooks/useSelectSearch.ts +0 -91
  1314. package/src/components/Select/hooks/useSelectState.ts +0 -104
  1315. package/src/components/Select/utils/__tests__/text.test.tsx +0 -104
  1316. package/src/components/Select/utils/text.ts +0 -26
  1317. package/src/components/__tests__/index.test.ts +0 -346
  1318. package/src/constants/__tests__/performance.test.ts +0 -91
  1319. package/src/hooks/__tests__/ServiceHooks.test.tsx +0 -725
  1320. package/src/hooks/__tests__/hooks.integration.test.tsx +0 -608
  1321. package/src/hooks/__tests__/index.unit.test.ts +0 -220
  1322. package/src/hooks/__tests__/useAppConfig.unit.test.ts +0 -406
  1323. package/src/hooks/__tests__/useComponentPerformance.unit.test.tsx +0 -328
  1324. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +0 -720
  1325. package/src/hooks/__tests__/useDataTableState.test.ts +0 -170
  1326. package/src/hooks/__tests__/useDebounce.unit.test.ts +0 -157
  1327. package/src/hooks/__tests__/useEvents.unit.test.ts +0 -227
  1328. package/src/hooks/__tests__/useFileDisplay.test.ts +0 -540
  1329. package/src/hooks/__tests__/useFileDisplay.unit.test.ts +0 -1109
  1330. package/src/hooks/__tests__/useFileUrl.unit.test.ts +0 -696
  1331. package/src/hooks/__tests__/useFileUrlCache.test.ts +0 -319
  1332. package/src/hooks/__tests__/useFocusManagement.unit.test.ts +0 -604
  1333. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +0 -613
  1334. package/src/hooks/__tests__/useFormDialog.test.ts +0 -307
  1335. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +0 -446
  1336. package/src/hooks/__tests__/useIsMobile.unit.test.ts +0 -317
  1337. package/src/hooks/__tests__/useKeyboardShortcuts.unit.test.ts +0 -907
  1338. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +0 -293
  1339. package/src/hooks/__tests__/useOrganisationSecurity.unit.test.tsx +0 -961
  1340. package/src/hooks/__tests__/useOrganisations.unit.test.ts +0 -369
  1341. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +0 -694
  1342. package/src/hooks/__tests__/usePermissionCache.test.ts +0 -506
  1343. package/src/hooks/__tests__/usePreventTabReload.test.ts +0 -307
  1344. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +0 -794
  1345. package/src/hooks/__tests__/usePublicEvent.test.ts +0 -670
  1346. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +0 -638
  1347. package/src/hooks/__tests__/usePublicFileDisplay.test.ts +0 -948
  1348. package/src/hooks/__tests__/usePublicRouteParams.unit.test.ts +0 -442
  1349. package/src/hooks/__tests__/useQueryCache.test.ts +0 -391
  1350. package/src/hooks/__tests__/useRBAC.unit.test.ts +0 -236
  1351. package/src/hooks/__tests__/useSessionDraft.test.ts +0 -556
  1352. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +0 -390
  1353. package/src/hooks/__tests__/useStorage.unit.test.ts +0 -721
  1354. package/src/hooks/__tests__/useToast.test.ts +0 -413
  1355. package/src/hooks/__tests__/useToast.unit.test.tsx +0 -481
  1356. package/src/hooks/__tests__/useZodForm.unit.test.tsx +0 -191
  1357. package/src/hooks/public/usePublicFileDisplay.test.ts +0 -723
  1358. package/src/hooks/public/usePublicFileDisplay.ts +0 -534
  1359. package/src/hooks/useFileDisplay.ts +0 -748
  1360. package/src/icons/__tests__/index.test.ts +0 -133
  1361. package/src/providers/OrganisationProvider.test.tsx +0 -40
  1362. package/src/providers/OrganisationProvider.tsx +0 -92
  1363. package/src/providers/__tests__/AuthProvider.test.tsx +0 -218
  1364. package/src/providers/__tests__/EventProvider.test.tsx +0 -487
  1365. package/src/providers/__tests__/InactivityProvider.test-helper.tsx +0 -65
  1366. package/src/providers/__tests__/InactivityProvider.test.tsx +0 -428
  1367. package/src/providers/__tests__/OrganisationProvider.test.tsx +0 -616
  1368. package/src/providers/__tests__/OrganisationProvider.wrapper.test.tsx +0 -591
  1369. package/src/providers/__tests__/ProviderLifecycle.test.tsx +0 -308
  1370. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +0 -503
  1371. package/src/providers/__tests__/index.test.ts +0 -138
  1372. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +0 -229
  1373. package/src/providers/services/__tests__/AuthServiceProvider.test.tsx +0 -638
  1374. package/src/providers/services/__tests__/EventServiceProvider.test.tsx +0 -839
  1375. package/src/providers/services/__tests__/InactivityServiceProvider.test.tsx +0 -662
  1376. package/src/providers/services/__tests__/OrganisationServiceProvider.test.tsx +0 -440
  1377. package/src/providers/services/__tests__/UnifiedAuthProvider.advanced.test.tsx +0 -435
  1378. package/src/providers/services/__tests__/UnifiedAuthProvider.appId.test.tsx +0 -408
  1379. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +0 -301
  1380. package/src/providers/services/__tests__/contexts.test.tsx +0 -281
  1381. package/src/providers/services/__tests__/useUnifiedAuth.test.tsx +0 -251
  1382. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +0 -429
  1383. package/src/rbac/__tests__/audit-batched.test.ts +0 -550
  1384. package/src/rbac/__tests__/auth-rbac-security.integration.test.tsx +0 -300
  1385. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +0 -517
  1386. package/src/rbac/__tests__/cache-invalidation.test.ts +0 -393
  1387. package/src/rbac/__tests__/engine.comprehensive.test.ts +0 -808
  1388. package/src/rbac/__tests__/performance.test.ts +0 -451
  1389. package/src/rbac/__tests__/rbac-core.test.tsx +0 -276
  1390. package/src/rbac/__tests__/rbac-engine-core-logic.test.ts +0 -387
  1391. package/src/rbac/__tests__/rbac-engine-simplified.test.ts +0 -252
  1392. package/src/rbac/__tests__/rbac-functions.test.ts +0 -646
  1393. package/src/rbac/__tests__/rbac-role-isolation.test.ts +0 -456
  1394. package/src/rbac/__tests__/scenarios.user-role.test.tsx +0 -271
  1395. package/src/rbac/components/__tests__/AccessDenied.test.tsx +0 -324
  1396. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +0 -1146
  1397. package/src/rbac/components/__tests__/PagePermissionGuard.performance.test.tsx +0 -231
  1398. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +0 -243
  1399. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +0 -1430
  1400. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +0 -185
  1401. package/src/rbac/hooks/__tests__/usePermissions.integration.test.ts +0 -427
  1402. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +0 -1179
  1403. package/src/rbac/hooks/permissions/__tests__/useAccessLevel.test.ts +0 -622
  1404. package/src/rbac/hooks/permissions/__tests__/useCan.test.ts +0 -798
  1405. package/src/rbac/hooks/permissions/__tests__/useMultiplePermissions.test.ts +0 -843
  1406. package/src/rbac/hooks/permissions/__tests__/usePermissions.test.ts +0 -545
  1407. package/src/rbac/utils/__tests__/clientSecurity.test.ts +0 -192
  1408. package/src/rbac/utils/__tests__/contextValidator.test.ts +0 -126
  1409. package/src/rbac/utils/__tests__/deep-equal.test.ts +0 -76
  1410. package/src/rbac/utils/__tests__/eventContext.test.ts +0 -386
  1411. package/src/services/__tests__/AuthService.edge-cases.test.ts +0 -746
  1412. package/src/services/__tests__/AuthService.restoreSession.test.ts +0 -59
  1413. package/src/services/__tests__/AuthService.test.ts +0 -1328
  1414. package/src/services/__tests__/BaseService.edge-cases.test.ts +0 -506
  1415. package/src/services/__tests__/BaseService.test.ts +0 -363
  1416. package/src/services/__tests__/EventService.edge-cases.test.ts +0 -633
  1417. package/src/services/__tests__/EventService.eventColours.test.ts +0 -64
  1418. package/src/services/__tests__/EventService.test.ts +0 -1018
  1419. package/src/services/__tests__/InactivityService.edge-cases.test.ts +0 -492
  1420. package/src/services/__tests__/InactivityService.lifecycle.test.ts +0 -406
  1421. package/src/services/__tests__/InactivityService.test.ts +0 -654
  1422. package/src/services/__tests__/OrganisationService.edge-cases.test.ts +0 -633
  1423. package/src/services/__tests__/OrganisationService.pagination.test.ts +0 -409
  1424. package/src/services/__tests__/OrganisationService.test.ts +0 -1176
  1425. package/src/services/interfaces/__tests__/IAuthService.test.ts +0 -190
  1426. package/src/services/interfaces/__tests__/IEventService.test.ts +0 -176
  1427. package/src/services/interfaces/__tests__/IInactivityService.test.ts +0 -183
  1428. package/src/services/interfaces/__tests__/IOrganisationService.test.ts +0 -207
  1429. package/src/theming/__tests__/parseEventColours.test.ts +0 -321
  1430. package/src/theming/__tests__/runtime.test.ts +0 -504
  1431. package/src/types/__tests__/core.test.ts +0 -397
  1432. package/src/types/__tests__/database-generated.test.ts +0 -78
  1433. package/src/types/__tests__/file-reference.test.ts +0 -351
  1434. package/src/types/__tests__/guards.test.ts +0 -246
  1435. package/src/types/__tests__/index.test.ts +0 -265
  1436. package/src/types/__tests__/organisation.roles.test.ts +0 -55
  1437. package/src/types/__tests__/organisation.test.ts +0 -1133
  1438. package/src/types/__tests__/theme.test.ts +0 -830
  1439. package/src/types/__tests__/type-validation.test.ts +0 -526
  1440. package/src/types/__tests__/validation.test.ts +0 -729
  1441. package/src/utils/__tests__/appConfig.unit.test.ts +0 -55
  1442. package/src/utils/__tests__/audit.unit.test.ts +0 -69
  1443. package/src/utils/__tests__/auth-utils.unit.test.ts +0 -70
  1444. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +0 -326
  1445. package/src/utils/__tests__/cn.unit.test.ts +0 -34
  1446. package/src/utils/__tests__/debugLogger.test.ts +0 -417
  1447. package/src/utils/__tests__/deviceFingerprint.unit.test.ts +0 -818
  1448. package/src/utils/__tests__/dynamicUtils.unit.test.ts +0 -331
  1449. package/src/utils/__tests__/formatDate.unit.test.ts +0 -109
  1450. package/src/utils/__tests__/formatting.unit.test.ts +0 -99
  1451. package/src/utils/__tests__/index.unit.test.ts +0 -251
  1452. package/src/utils/__tests__/lazyLoad.unit.test.tsx +0 -320
  1453. package/src/utils/__tests__/logger.unit.test.ts +0 -398
  1454. package/src/utils/__tests__/organisationContext.unit.test.ts +0 -191
  1455. package/src/utils/__tests__/performanceBenchmark.test.ts +0 -174
  1456. package/src/utils/__tests__/performanceBudgets.unit.test.ts +0 -288
  1457. package/src/utils/__tests__/permissionTypes.unit.test.ts +0 -250
  1458. package/src/utils/__tests__/permissionUtils.unit.test.ts +0 -362
  1459. package/src/utils/__tests__/request-deduplication.test.ts +0 -349
  1460. package/src/utils/__tests__/sanitization.unit.test.ts +0 -346
  1461. package/src/utils/__tests__/schemaUtils.unit.test.ts +0 -441
  1462. package/src/utils/__tests__/secureDataAccess.unit.test.ts +0 -334
  1463. package/src/utils/__tests__/secureErrors.unit.test.ts +0 -390
  1464. package/src/utils/__tests__/secureStorage.unit.test.ts +0 -289
  1465. package/src/utils/__tests__/security.unit.test.ts +0 -149
  1466. package/src/utils/__tests__/securityMonitor.unit.test.ts +0 -276
  1467. package/src/utils/__tests__/sessionTracking.unit.test.ts +0 -218
  1468. package/src/utils/__tests__/timezone.test.ts +0 -345
  1469. package/src/utils/__tests__/validation.unit.test.ts +0 -307
  1470. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -555
  1471. package/src/utils/core/__tests__/cn.test.ts +0 -66
  1472. package/src/utils/core/__tests__/debugLogger.test.ts +0 -113
  1473. package/src/utils/core/__tests__/logger.test.ts +0 -217
  1474. package/src/utils/dynamic/__tests__/dynamicUtils.test.ts +0 -185
  1475. package/src/utils/dynamic/__tests__/lazyLoad.test.tsx +0 -156
  1476. package/src/utils/file-reference/__tests__/file-reference.test.ts +0 -1313
  1477. package/src/utils/performance/__tests__/bundleAnalysis.test.ts +0 -148
  1478. package/src/utils/performance/__tests__/performanceBenchmark.test.ts +0 -251
  1479. package/src/utils/performance/__tests__/performanceBudgets.test.ts +0 -241
  1480. package/src/utils/permissions/__tests__/permissionTypes.test.ts +0 -149
  1481. package/src/utils/persistence/__tests__/keyDerivation.test.ts +0 -306
  1482. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +0 -271
  1483. package/src/utils/storage/__tests__/config.unit.test.ts +0 -239
  1484. package/src/utils/storage/__tests__/index.unit.test.ts +0 -68
  1485. package/src/utils/validation/__tests__/common.test.ts +0 -115
  1486. package/src/utils/validation/__tests__/csrf.test.ts +0 -170
  1487. package/src/utils/validation/__tests__/htmlSanitization.unit.test.ts +0 -618
  1488. package/src/utils/validation/__tests__/passwordSchema.test.ts +0 -164
  1489. package/src/utils/validation/__tests__/schema.test.ts +0 -127
  1490. package/src/utils/validation/__tests__/sqlInjectionProtection.test.ts +0 -165
  1491. package/src/utils/validation/__tests__/user.test.ts +0 -173
  1492. package/src/utils/validation/__tests__/validation.test.ts +0 -197
  1493. package/src/utils/validation/__tests__/validationUtils.test.ts +0 -294
  1494. /package/src/components/DataTable/{components/__tests__ → ui}/COVERAGE_NOTE.md +0 -0
  1495. /package/src/components/DataTable/utils/{__tests__/COVERAGE_NOTE.md → COVERAGE_NOTE.md} +0 -0
  1496. /package/src/hooks/{__tests__/useApiFetch.unit.test.ts → useApiFetch.unit.test.ts} +0 -0
  1497. /package/src/providers/{__tests__/README.md → README.md} +0 -0
  1498. /package/src/rbac/{__tests__/index.test.ts → index.test.ts} +0 -0
  1499. /package/src/rbac/{__tests__/rbac-integration.test.ts → rbac-integration.test.ts} +0 -0
  1500. /package/src/types/{__tests__/README.md → README.md} +0 -0
@@ -0,0 +1,2946 @@
1
+ import { setPrintAppName } from './chunk-D6BMFMQZ.js';
2
+ import { isRBACInitialized, setupRBAC } from './chunk-YFGNMB67.js';
3
+ import { assertOrganisationId, assertUserId } from './chunk-4SXLQIZO.js';
4
+ import { secureStorage } from './chunk-RMLY6KB5.js';
5
+ import { createLogger, logger } from './chunk-BTHN5MKC.js';
6
+ import { err, ok } from './chunk-44CNXN4P.js';
7
+ import { createContext, useRef, useEffect, useState, useMemo, useContext, useReducer, useCallback } from 'react';
8
+ import { AuthError } from '@supabase/supabase-js';
9
+ import { jsx } from 'react/jsx-runtime';
10
+ import { flushSync } from 'react-dom';
11
+
12
+ // src/services/base/BaseService.ts
13
+ var BaseService = class {
14
+ constructor() {
15
+ this.subscribers = [];
16
+ this.isInitialized = false;
17
+ }
18
+ /**
19
+ * Subscribe to state changes
20
+ * @param callback Function to call when state changes
21
+ * @returns Unsubscribe function
22
+ */
23
+ subscribe(callback) {
24
+ this.subscribers.push(callback);
25
+ return () => {
26
+ const index = this.subscribers.indexOf(callback);
27
+ if (index > -1) {
28
+ this.subscribers.splice(index, 1);
29
+ }
30
+ };
31
+ }
32
+ /**
33
+ * Notify all subscribers of state changes
34
+ * This triggers React re-renders
35
+ */
36
+ notify() {
37
+ this.subscribers.forEach((callback) => {
38
+ try {
39
+ callback();
40
+ } catch (error) {
41
+ logger.error("BaseService", "Error in subscriber callback:", error);
42
+ }
43
+ });
44
+ }
45
+ /**
46
+ * Initialize the service
47
+ * Override in subclasses to implement initialization logic
48
+ */
49
+ async initialize() {
50
+ if (this.isInitialized) {
51
+ return;
52
+ }
53
+ await this.doInitialize();
54
+ this.isInitialized = true;
55
+ }
56
+ /**
57
+ * Cleanup the service
58
+ * Override in subclasses to implement cleanup logic
59
+ */
60
+ cleanup() {
61
+ this.subscribers = [];
62
+ this.doCleanup();
63
+ this.isInitialized = false;
64
+ }
65
+ /**
66
+ * Check if service is initialized
67
+ */
68
+ getInitialized() {
69
+ return this.isInitialized;
70
+ }
71
+ /**
72
+ * Reset initialization state (allows re-initialization)
73
+ * Use when dependencies change and service needs to re-initialize
74
+ */
75
+ resetInitialization() {
76
+ this.isInitialized = false;
77
+ }
78
+ };
79
+
80
+ // src/utils/security/auth-utils.ts
81
+ function toApiError(error) {
82
+ const message = error.message || "An unexpected error occurred";
83
+ const code = "status" in error && typeof error.status === "number" ? `AUTH_${error.status}` : error.name || "AUTH_ERROR";
84
+ return { code, message };
85
+ }
86
+
87
+ // src/services/AuthService.ts
88
+ var _AuthService = class _AuthService extends BaseService {
89
+ // Track previous auth state to detect transitions
90
+ constructor(supabaseClient, appName) {
91
+ super();
92
+ this.user = null;
93
+ this.session = null;
94
+ this.authLoading = false;
95
+ this.authError = null;
96
+ this.supabaseClient = null;
97
+ this.authStateSubscription = null;
98
+ this.sessionRestorationState = {
99
+ isRestoring: false,
100
+ restorationComplete: false,
101
+ restorationError: null
102
+ };
103
+ this.restorationTimeoutId = null;
104
+ // Increased timeout to handle hard refresh scenarios where localStorage access
105
+ // and session restoration may take longer, especially with organisation/event context
106
+ this.restorationTimeoutMs = 1e4;
107
+ // 10 seconds (increased from 5)
108
+ this.restorationStartTime = null;
109
+ this.appName = void 0;
110
+ this.errorHandler = null;
111
+ this.unhandledRejectionHandler = null;
112
+ this.wasAuthenticatedRef = false;
113
+ this.instanceId = ++_AuthService.instanceCount;
114
+ this.supabaseClient = supabaseClient;
115
+ this.appName = appName;
116
+ }
117
+ getInstanceId() {
118
+ return this.instanceId;
119
+ }
120
+ // Auth state getters
121
+ getUser() {
122
+ return this.user;
123
+ }
124
+ getSession() {
125
+ return this.session;
126
+ }
127
+ isAuthenticated() {
128
+ return !!(this.user && this.session);
129
+ }
130
+ isLoading() {
131
+ return this.authLoading;
132
+ }
133
+ getError() {
134
+ return this.authError;
135
+ }
136
+ getSupabaseClient() {
137
+ return this.supabaseClient;
138
+ }
139
+ getSessionRestorationState() {
140
+ return { ...this.sessionRestorationState };
141
+ }
142
+ // Auth methods
143
+ async signIn(email, password) {
144
+ if (!this.supabaseClient) {
145
+ const error = new AuthError("Supabase client not available");
146
+ this.authError = error;
147
+ this.notify();
148
+ return err(toApiError(error));
149
+ }
150
+ try {
151
+ const { data, error } = await this.supabaseClient.auth.signInWithPassword({
152
+ email,
153
+ password: password || ""
154
+ });
155
+ if (error) {
156
+ this.authError = error;
157
+ this.user = null;
158
+ this.session = null;
159
+ this.notify();
160
+ return err(toApiError(error));
161
+ }
162
+ this.authError = null;
163
+ this.user = data.user;
164
+ this.session = data.session;
165
+ if (!this.wasAuthenticatedRef && data.user) {
166
+ this.clearPersistenceOnLogin(null, true);
167
+ this.wasAuthenticatedRef = true;
168
+ }
169
+ this.notify();
170
+ return ok({ user: data.user, session: data.session });
171
+ } catch (error) {
172
+ const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
173
+ this.authError = authError;
174
+ this.user = null;
175
+ this.session = null;
176
+ this.notify();
177
+ return err(toApiError(authError));
178
+ }
179
+ }
180
+ async signUp(email, password) {
181
+ if (!this.supabaseClient) {
182
+ const error = new AuthError("Supabase client not available");
183
+ this.authError = error;
184
+ this.notify();
185
+ return err(toApiError(error));
186
+ }
187
+ try {
188
+ const { data, error } = await this.supabaseClient.auth.signUp({
189
+ email,
190
+ password
191
+ });
192
+ if (error) {
193
+ this.authError = error;
194
+ this.user = null;
195
+ this.session = null;
196
+ this.notify();
197
+ return err(toApiError(error));
198
+ }
199
+ this.authError = null;
200
+ this.user = data.user;
201
+ this.session = data.session;
202
+ if (!this.wasAuthenticatedRef && data.user) {
203
+ this.clearPersistenceOnLogin(null, true);
204
+ this.wasAuthenticatedRef = true;
205
+ }
206
+ this.notify();
207
+ return ok({ user: data.user, session: data.session });
208
+ } catch (error) {
209
+ const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
210
+ this.authError = authError;
211
+ this.user = null;
212
+ this.session = null;
213
+ this.notify();
214
+ return err(toApiError(authError));
215
+ }
216
+ }
217
+ async signOut() {
218
+ if (!this.supabaseClient) {
219
+ const error = new AuthError("Supabase client not available");
220
+ this.authError = error;
221
+ this.notify();
222
+ return err(toApiError(error));
223
+ }
224
+ const clearLocalState = () => {
225
+ this.authError = null;
226
+ this.user = null;
227
+ this.session = null;
228
+ try {
229
+ sessionStorage.clear();
230
+ } catch (storageError) {
231
+ logger.warn("AuthService", "Failed to clear sessionStorage", { error: storageError });
232
+ }
233
+ this.notify();
234
+ };
235
+ try {
236
+ const { error } = await this.supabaseClient.auth.signOut();
237
+ if (error) {
238
+ logger.warn("AuthService", "signOut (global) failed, clearing local state and trying local scope", {
239
+ message: error.message,
240
+ status: error.status
241
+ });
242
+ clearLocalState();
243
+ const { error: localError } = await this.supabaseClient.auth.signOut({ scope: "local" });
244
+ if (localError) {
245
+ logger.warn("AuthService", "signOut (local) also failed", { message: localError.message });
246
+ }
247
+ return err(toApiError(error));
248
+ }
249
+ clearLocalState();
250
+ return ok({ user: null, session: null });
251
+ } catch (error) {
252
+ logger.warn("AuthService", "signOut threw, clearing local state and trying local scope", {
253
+ message: error instanceof Error ? error.message : String(error)
254
+ });
255
+ clearLocalState();
256
+ try {
257
+ await this.supabaseClient.auth.signOut({ scope: "local" });
258
+ } catch (_localError) {
259
+ }
260
+ const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
261
+ this.authError = authError;
262
+ return err(toApiError(authError));
263
+ }
264
+ }
265
+ async resetPassword(email) {
266
+ if (!this.supabaseClient) {
267
+ const error = new AuthError("Supabase client not available");
268
+ this.authError = error;
269
+ this.notify();
270
+ return err(toApiError(error));
271
+ }
272
+ try {
273
+ const { error } = await this.supabaseClient.auth.resetPasswordForEmail(email);
274
+ if (error) {
275
+ this.authError = error;
276
+ this.notify();
277
+ return err(toApiError(error));
278
+ }
279
+ this.authError = null;
280
+ this.notify();
281
+ return ok({ user: this.user, session: this.session });
282
+ } catch (error) {
283
+ const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
284
+ this.authError = authError;
285
+ this.notify();
286
+ return err(toApiError(authError));
287
+ }
288
+ }
289
+ async updatePassword(password) {
290
+ if (!this.supabaseClient) {
291
+ const error = new AuthError("Supabase client not available");
292
+ this.authError = error;
293
+ this.notify();
294
+ return err(toApiError(error));
295
+ }
296
+ try {
297
+ const { error } = await this.supabaseClient.auth.updateUser({
298
+ password
299
+ });
300
+ if (error) {
301
+ this.authError = error;
302
+ this.notify();
303
+ return err(toApiError(error));
304
+ }
305
+ this.authError = null;
306
+ this.notify();
307
+ return ok({ user: this.user, session: this.session });
308
+ } catch (error) {
309
+ const authError = error instanceof AuthError ? error : error;
310
+ this.authError = authError;
311
+ this.notify();
312
+ return err(toApiError(authError));
313
+ }
314
+ }
315
+ async refreshSession() {
316
+ if (!this.supabaseClient) {
317
+ const error = new AuthError("Supabase client not available");
318
+ this.authError = error;
319
+ this.notify();
320
+ return err(toApiError(error));
321
+ }
322
+ try {
323
+ const { data, error } = await this.supabaseClient.auth.refreshSession();
324
+ if (error) {
325
+ this.authError = error;
326
+ this.user = null;
327
+ this.session = null;
328
+ this.notify();
329
+ return err(toApiError(error));
330
+ }
331
+ this.authError = null;
332
+ if (data?.user && data?.session) {
333
+ this.user = data.user;
334
+ this.session = data.session;
335
+ } else {
336
+ this.user = null;
337
+ this.session = null;
338
+ }
339
+ this.notify();
340
+ return ok({
341
+ user: data?.user && data?.session ? data.user : null,
342
+ session: data?.session ?? null
343
+ });
344
+ } catch (error) {
345
+ const authError = error instanceof AuthError ? error : new AuthError(error instanceof Error ? error.message : "Authentication failed");
346
+ this.authError = authError;
347
+ this.user = null;
348
+ this.session = null;
349
+ this.notify();
350
+ return err(toApiError(authError));
351
+ }
352
+ }
353
+ // Lifecycle methods
354
+ async initialize() {
355
+ await super.initialize();
356
+ this.authLoading = true;
357
+ this.notify();
358
+ await this.setupAuthStateListener();
359
+ await this.restoreSession();
360
+ }
361
+ cleanup() {
362
+ if (this.authStateSubscription) {
363
+ this.authStateSubscription.unsubscribe();
364
+ this.authStateSubscription = null;
365
+ }
366
+ this.clearRestorationTimeout();
367
+ this.restorationStartTime = null;
368
+ this.sessionRestorationState = {
369
+ isRestoring: false,
370
+ restorationComplete: false,
371
+ restorationError: null
372
+ };
373
+ this.authLoading = false;
374
+ super.cleanup();
375
+ }
376
+ async doInitialize() {
377
+ this.setupErrorHandlers();
378
+ }
379
+ doCleanup() {
380
+ this.removeErrorHandlers();
381
+ }
382
+ startSessionRestoration() {
383
+ this.clearRestorationTimeout();
384
+ this.sessionRestorationState = {
385
+ isRestoring: true,
386
+ restorationComplete: false,
387
+ restorationError: null
388
+ };
389
+ this.authLoading = true;
390
+ this.restorationStartTime = Date.now();
391
+ this.notify();
392
+ this.restorationTimeoutId = setTimeout(() => {
393
+ logger.warn("AuthService", "Session restoration timed out after", this.restorationTimeoutMs, "ms");
394
+ const timeoutError = new Error(`Session restoration timed out after ${this.restorationTimeoutMs}ms`);
395
+ timeoutError.name = "SessionRestorationTimeoutError";
396
+ this.finishSessionRestoration(timeoutError);
397
+ }, this.restorationTimeoutMs);
398
+ }
399
+ finishSessionRestoration(error) {
400
+ if (!this.sessionRestorationState.isRestoring && !error) {
401
+ return;
402
+ }
403
+ this.clearRestorationTimeout();
404
+ this.restorationStartTime = null;
405
+ const restorationComplete = !error;
406
+ this.sessionRestorationState = {
407
+ isRestoring: false,
408
+ restorationComplete,
409
+ restorationError: error ?? null
410
+ };
411
+ this.authLoading = false;
412
+ if (error) {
413
+ logger.warn("AuthService", "Session restoration finished with error:", error);
414
+ }
415
+ this.notify();
416
+ }
417
+ clearRestorationTimeout() {
418
+ if (this.restorationTimeoutId) {
419
+ clearTimeout(this.restorationTimeoutId);
420
+ this.restorationTimeoutId = null;
421
+ }
422
+ }
423
+ /**
424
+ * Clear pace-core persistence entries from sessionStorage
425
+ * This includes dialog, form, and datatable persistence
426
+ *
427
+ * @param userId - Optional user ID to clear only that user's persistence.
428
+ * If not provided, clears all pace-core persistence (for user changes).
429
+ * @param clearUnscoped - If true, also clears old unscoped keys (without :user: prefix)
430
+ */
431
+ clearPersistenceOnLogin(userId, clearUnscoped = true) {
432
+ if (typeof window === "undefined" || !window.sessionStorage) {
433
+ return;
434
+ }
435
+ try {
436
+ const keysToRemove = [];
437
+ for (let i = 0; i < sessionStorage.length; i++) {
438
+ const key = sessionStorage.key(i);
439
+ if (key && (key.startsWith("pace-core:draft:") || key.startsWith("pace-core:dialog:"))) {
440
+ if (userId && !key.includes(`:user:${userId}`)) {
441
+ if (clearUnscoped && !key.includes(":user:")) {
442
+ keysToRemove.push(key);
443
+ }
444
+ continue;
445
+ }
446
+ keysToRemove.push(key);
447
+ }
448
+ }
449
+ keysToRemove.forEach((key) => {
450
+ try {
451
+ sessionStorage.removeItem(key);
452
+ } catch (error) {
453
+ logger.warn("AuthService", `Failed to remove persistence key: ${key}`, error);
454
+ }
455
+ });
456
+ } catch (error) {
457
+ logger.warn("AuthService", `Failed to clear persistence [ID:${this.instanceId}]:`, error);
458
+ }
459
+ }
460
+ handleSignedOut(session) {
461
+ this.session = null;
462
+ this.user = null;
463
+ this.authError = null;
464
+ this.wasAuthenticatedRef = false;
465
+ if (session?.user) {
466
+ this.trackSession("logout", session).catch((err2) => {
467
+ logger.warn("AuthService", `Failed to track logout session [ID:${this.instanceId}]:`, err2);
468
+ });
469
+ }
470
+ }
471
+ handleSignedInOrTokenRefreshed(event, session, wasAuthenticated, isNowAuthenticated, userChanged, previousUserId) {
472
+ this.session = session;
473
+ this.user = session?.user ?? null;
474
+ if (session?.user) {
475
+ this.authError = null;
476
+ }
477
+ if (!wasAuthenticated && isNowAuthenticated && event === "SIGNED_IN") {
478
+ this.clearPersistenceOnLogin(null, true);
479
+ } else if (userChanged && previousUserId) {
480
+ this.clearPersistenceOnLogin(previousUserId, true);
481
+ }
482
+ this.wasAuthenticatedRef = isNowAuthenticated;
483
+ if (event === "SIGNED_IN" && session?.user) {
484
+ this.trackSession("login", session).catch((err2) => {
485
+ logger.warn("AuthService", `Failed to track login session [ID:${this.instanceId}]:`, err2);
486
+ });
487
+ }
488
+ }
489
+ handleInitialSession(session, wasAuthenticated) {
490
+ if (session) {
491
+ const previousUserId = this.user?.id ?? null;
492
+ const newUserId = session.user?.id ?? null;
493
+ const userChanged = previousUserId !== null && newUserId !== null && previousUserId !== newUserId;
494
+ this.session = session;
495
+ this.user = session.user ?? null;
496
+ this.authError = null;
497
+ if (userChanged && previousUserId) {
498
+ this.clearPersistenceOnLogin(previousUserId, true);
499
+ } else if (!wasAuthenticated && !!session.user) {
500
+ this.clearPersistenceOnLogin(null, true);
501
+ }
502
+ this.wasAuthenticatedRef = !!session.user;
503
+ const hasTimeoutError = this.sessionRestorationState.restorationError?.name === "SessionRestorationTimeoutError";
504
+ if (this.sessionRestorationState.isRestoring || this.sessionRestorationState.restorationError || hasTimeoutError && session) {
505
+ this.finishSessionRestoration();
506
+ }
507
+ } else {
508
+ this.wasAuthenticatedRef = false;
509
+ if (this.sessionRestorationState.isRestoring) {
510
+ this.finishSessionRestoration();
511
+ }
512
+ }
513
+ this.authLoading = false;
514
+ this.notify();
515
+ }
516
+ async setupAuthStateListener() {
517
+ if (!this.supabaseClient) {
518
+ this.authLoading = false;
519
+ this.notify();
520
+ return;
521
+ }
522
+ try {
523
+ const subscription = this.supabaseClient.auth.onAuthStateChange(
524
+ (event, session) => {
525
+ try {
526
+ const wasAuthenticated = this.wasAuthenticatedRef;
527
+ const isNowAuthenticated = !!session?.user;
528
+ const previousUserId = this.user?.id ?? null;
529
+ const newUserId = session?.user?.id ?? null;
530
+ const userChanged = previousUserId !== null && newUserId !== null && previousUserId !== newUserId;
531
+ if (event === "SIGNED_OUT") {
532
+ this.handleSignedOut(session);
533
+ } else if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
534
+ this.handleSignedInOrTokenRefreshed(
535
+ event,
536
+ session,
537
+ wasAuthenticated,
538
+ isNowAuthenticated,
539
+ userChanged,
540
+ previousUserId
541
+ );
542
+ } else if (event === "INITIAL_SESSION") {
543
+ this.handleInitialSession(session, wasAuthenticated);
544
+ return;
545
+ }
546
+ this.authLoading = false;
547
+ this.notify();
548
+ } catch (error) {
549
+ logger.warn("AuthService", `Error in auth state change handler [ID:${this.instanceId}]:`, error);
550
+ this.authLoading = false;
551
+ this.notify();
552
+ }
553
+ }
554
+ );
555
+ this.authStateSubscription = subscription.data.subscription;
556
+ } catch (error) {
557
+ logger.error("AuthService", "Failed to setup auth state listener:", error);
558
+ throw error;
559
+ }
560
+ }
561
+ async restoreSession() {
562
+ if (!this.supabaseClient) {
563
+ const error = new Error("Supabase client not available during session restoration");
564
+ logger.error("AuthService", "Unable to restore session:", error);
565
+ this.finishSessionRestoration(error);
566
+ return;
567
+ }
568
+ this.startSessionRestoration();
569
+ try {
570
+ let currentSession = null;
571
+ let sessionError = null;
572
+ try {
573
+ const { data, error } = await this.supabaseClient.auth.getSession();
574
+ currentSession = data?.session ?? null;
575
+ sessionError = error ?? null;
576
+ } catch (_error) {
577
+ currentSession = null;
578
+ sessionError = null;
579
+ }
580
+ if (sessionError) {
581
+ this.authError = sessionError;
582
+ try {
583
+ const { data, error } = await this.supabaseClient.auth.getUser();
584
+ const currentUser = data?.user ?? null;
585
+ const userError = error ?? null;
586
+ if (currentUser) {
587
+ this.user = currentUser;
588
+ this.session = null;
589
+ }
590
+ if (userError && !this.authError) {
591
+ this.authError = userError;
592
+ }
593
+ } catch (_getUserError) {
594
+ }
595
+ }
596
+ if (currentSession) {
597
+ this.session = currentSession;
598
+ this.user = currentSession.user;
599
+ this.authError = null;
600
+ } else if (!sessionError) {
601
+ this.session = null;
602
+ this.user = null;
603
+ this.authError = null;
604
+ }
605
+ setTimeout(() => {
606
+ if (this.sessionRestorationState.isRestoring && !this.sessionRestorationState.restorationComplete) {
607
+ logger.debug("AuthService", "INITIAL_SESSION event did not fire, finishing restoration");
608
+ this.finishSessionRestoration();
609
+ }
610
+ }, 100);
611
+ } catch (error) {
612
+ const restorationError = error instanceof Error ? error : new Error("Unknown error during auth initialization");
613
+ logger.error("AuthService", "Error during auth initialization:", restorationError);
614
+ if (restorationError instanceof AuthError) {
615
+ this.authError = restorationError;
616
+ }
617
+ this.finishSessionRestoration(restorationError);
618
+ }
619
+ }
620
+ /**
621
+ * Automatically track user session using rbac_session_track
622
+ * This method is called automatically on SIGNED_IN and SIGNED_OUT events.
623
+ * It's non-blocking and failures are logged as warnings.
624
+ */
625
+ async trackSession(sessionType, session) {
626
+ if (!this.supabaseClient || !session?.user) {
627
+ return;
628
+ }
629
+ try {
630
+ let appId = void 0;
631
+ if (this.appName) {
632
+ const { data, error: error2 } = await this.supabaseClient.from("rbac_apps").select("id").eq("name", this.appName).eq("is_active", true).single();
633
+ if (!error2 && data) {
634
+ appId = data.id;
635
+ }
636
+ }
637
+ const ipAddress = void 0;
638
+ const userAgent = typeof navigator !== "undefined" ? navigator.userAgent : void 0;
639
+ const deviceFingerprint = void 0;
640
+ const { error } = await this.supabaseClient.rpc("rbac_session_track", {
641
+ p_user_id: session.user.id,
642
+ p_session_type: sessionType,
643
+ p_event_id: null,
644
+ // Event ID should come from context, not auth service
645
+ p_app_id: appId,
646
+ p_ip_address: ipAddress,
647
+ p_user_agent: userAgent,
648
+ p_device_fingerprint: deviceFingerprint
649
+ });
650
+ if (error) {
651
+ logger.warn("AuthService", `Failed to track ${sessionType} session:`, error);
652
+ }
653
+ } catch (error) {
654
+ logger.warn("AuthService", `Error tracking ${sessionType} session:`, error);
655
+ }
656
+ }
657
+ setupErrorHandlers() {
658
+ if (typeof window === "undefined") return;
659
+ this.errorHandler = (event) => {
660
+ if (event.error?.message?.includes("AuthSessionMissingError") || event.error?.message?.includes("Auth session missing")) {
661
+ logger.warn("AuthService", "Suppressing AuthSessionMissingError during logout");
662
+ event.preventDefault();
663
+ return false;
664
+ }
665
+ };
666
+ this.unhandledRejectionHandler = (event) => {
667
+ if (event.reason?.message?.includes("AuthSessionMissingError") || event.reason?.message?.includes("Auth session missing")) {
668
+ logger.warn("AuthService", "Suppressing unhandled AuthSessionMissingError");
669
+ event.preventDefault();
670
+ return false;
671
+ }
672
+ };
673
+ window.addEventListener("error", this.errorHandler);
674
+ window.addEventListener("unhandledrejection", this.unhandledRejectionHandler);
675
+ }
676
+ removeErrorHandlers() {
677
+ if (typeof window === "undefined") return;
678
+ if (this.errorHandler) {
679
+ window.removeEventListener("error", this.errorHandler);
680
+ this.errorHandler = null;
681
+ }
682
+ if (this.unhandledRejectionHandler) {
683
+ window.removeEventListener("unhandledrejection", this.unhandledRejectionHandler);
684
+ this.unhandledRejectionHandler = null;
685
+ }
686
+ }
687
+ };
688
+ _AuthService.instanceCount = 0;
689
+ var AuthService = _AuthService;
690
+ var AuthServiceContext = createContext(null);
691
+ function AuthServiceProvider({ children, supabaseClient, appName }) {
692
+ const authServiceRef = useRef(null);
693
+ if (!authServiceRef.current) {
694
+ authServiceRef.current = new AuthService(supabaseClient, appName);
695
+ }
696
+ const authService = authServiceRef.current;
697
+ useEffect(() => {
698
+ }, [authService, supabaseClient, appName]);
699
+ const [sessionRestoration, setSessionRestoration] = useState(
700
+ () => authService.getSessionRestorationState()
701
+ );
702
+ useEffect(() => {
703
+ const unsubscribe = authService.subscribe(() => {
704
+ const restorationState = authService.getSessionRestorationState();
705
+ setSessionRestoration(restorationState);
706
+ });
707
+ return () => {
708
+ unsubscribe();
709
+ };
710
+ }, [authService]);
711
+ useEffect(() => {
712
+ const urlParams = new URLSearchParams(window.location.search);
713
+ const sessionParam = urlParams.get("session");
714
+ const sessionTokenParam = urlParams.get("session_token");
715
+ if ((sessionParam || sessionTokenParam) && supabaseClient) {
716
+ const restoreSession = async () => {
717
+ try {
718
+ if (sessionParam) {
719
+ const sessionData = JSON.parse(atob(sessionParam));
720
+ logger.info("AuthServiceProvider", "Restoring session from URL parameter");
721
+ const { data, error } = await supabaseClient.auth.setSession({
722
+ access_token: sessionData.access_token,
723
+ refresh_token: sessionData.refresh_token
724
+ });
725
+ if (error) {
726
+ logger.error("AuthServiceProvider", "Failed to restore session from URL:", error);
727
+ } else if (data.session) {
728
+ logger.info("AuthServiceProvider", "Session successfully restored from URL parameter", {
729
+ userId: data.session.user.id,
730
+ expiresAt: data.session.expires_at
731
+ });
732
+ const newUrl = new URL(window.location.href);
733
+ newUrl.searchParams.delete("session");
734
+ window.history.replaceState({}, "", newUrl.toString());
735
+ }
736
+ } else if (sessionTokenParam) {
737
+ logger.warn("AuthServiceProvider", "Using fallback session_token parameter (less reliable)");
738
+ const { data: { user }, error } = await supabaseClient.auth.getUser(sessionTokenParam);
739
+ if (!error && user) {
740
+ logger.info("AuthServiceProvider", "Session token verified, but full session restoration requires refresh_token");
741
+ } else {
742
+ logger.error("AuthServiceProvider", "Failed to verify session token:", error);
743
+ }
744
+ const newUrl = new URL(window.location.href);
745
+ newUrl.searchParams.delete("session_token");
746
+ window.history.replaceState({}, "", newUrl.toString());
747
+ }
748
+ } catch (error) {
749
+ logger.error("AuthServiceProvider", "Error restoring session from URL:", error);
750
+ const newUrl = new URL(window.location.href);
751
+ newUrl.searchParams.delete("session");
752
+ newUrl.searchParams.delete("session_token");
753
+ window.history.replaceState({}, "", newUrl.toString());
754
+ }
755
+ };
756
+ void restoreSession();
757
+ }
758
+ }, [supabaseClient]);
759
+ useEffect(() => {
760
+ const initTimer = setTimeout(() => {
761
+ authService.initialize().catch((error) => {
762
+ logger.error("AuthServiceProvider", "Failed to initialize auth service:", error);
763
+ });
764
+ }, 200);
765
+ return () => {
766
+ clearTimeout(initTimer);
767
+ authService.cleanup();
768
+ };
769
+ }, [authService]);
770
+ const contextValue = useMemo(() => ({
771
+ authService,
772
+ sessionRestoration
773
+ }), [authService, sessionRestoration]);
774
+ return /* @__PURE__ */ jsx(AuthServiceContext.Provider, { value: contextValue, children });
775
+ }
776
+ var OrganisationServiceContext = createContext(null);
777
+
778
+ // src/services/OrganisationService.ts
779
+ var _OrganisationService = class _OrganisationService extends BaseService {
780
+ constructor(supabaseClient, user, session) {
781
+ super();
782
+ this._selectedOrganisation = null;
783
+ this._organisations = [];
784
+ this._userMemberships = [];
785
+ this._roleMapState = /* @__PURE__ */ new Map();
786
+ this._isLoading = false;
787
+ this._error = null;
788
+ this._isSuperAdmin = false;
789
+ // Cache super admin status
790
+ this._isContextReady = false;
791
+ this.retryCount = 0;
792
+ // Dependencies
793
+ this.supabaseClient = null;
794
+ this.user = null;
795
+ this.session = null;
796
+ // Internal state management
797
+ this.isLoadingRef = false;
798
+ this.lastLoadTimeRef = 0;
799
+ this.hasFailedRef = false;
800
+ this.abortControllerRef = null;
801
+ this.instanceId = ++_OrganisationService.instanceCount;
802
+ this.supabaseClient = supabaseClient;
803
+ this.user = user;
804
+ this.session = session;
805
+ }
806
+ getInstanceId() {
807
+ return this.instanceId;
808
+ }
809
+ // Interface implementation
810
+ getSelectedOrganisation() {
811
+ return this._selectedOrganisation;
812
+ }
813
+ getOrganisations() {
814
+ return this._organisations;
815
+ }
816
+ getUserMemberships() {
817
+ return this._userMemberships;
818
+ }
819
+ isLoading() {
820
+ return this._isLoading;
821
+ }
822
+ getError() {
823
+ return this._error;
824
+ }
825
+ hasValidOrganisationContext() {
826
+ return !!(this._selectedOrganisation && !this._isLoading && !this._error && this._isContextReady);
827
+ }
828
+ isContextReady() {
829
+ return this._isContextReady;
830
+ }
831
+ // Additional methods for testing
832
+ setSelectedOrganisation(organisation) {
833
+ if (organisation && this._organisations.length > 0) {
834
+ if (!this._isSuperAdmin) {
835
+ const isValidOrg = this._organisations.some((org) => org.id === organisation.id);
836
+ if (!isValidOrg) {
837
+ logger.warn("OrganisationService", "Attempted to set invalid organisation - not in user's accessible organisations", {
838
+ organisationId: organisation.id,
839
+ organisationName: organisation.name,
840
+ accessibleOrgIds: this._organisations.map((o) => o.id)
841
+ });
842
+ return;
843
+ }
844
+ }
845
+ }
846
+ this._selectedOrganisation = organisation;
847
+ if (organisation) {
848
+ localStorage.setItem("pace-core-selected-organisation", JSON.stringify(organisation));
849
+ this.setDatabaseOrganisationContext(organisation);
850
+ } else {
851
+ localStorage.removeItem("pace-core-selected-organisation");
852
+ this._isContextReady = false;
853
+ }
854
+ this.notify();
855
+ }
856
+ // For testing: expose dependencies
857
+ getDependencies() {
858
+ return {
859
+ user: this.user,
860
+ session: this.session,
861
+ supabaseClient: this.supabaseClient
862
+ };
863
+ }
864
+ // For testing: manually set state
865
+ setTestState(organisations, memberships, roleMap, selectedOrg = null) {
866
+ this._organisations = organisations;
867
+ this._userMemberships = memberships;
868
+ this._roleMapState = roleMap;
869
+ if (selectedOrg) {
870
+ this._selectedOrganisation = selectedOrg;
871
+ } else if (organisations.length > 0) {
872
+ this._selectedOrganisation = organisations[0];
873
+ }
874
+ this._isLoading = false;
875
+ this._error = null;
876
+ this.notify();
877
+ }
878
+ // Update dependencies
879
+ updateDependencies(user, session) {
880
+ const previousUserId = this.user?.id || null;
881
+ const newUserId = user?.id || null;
882
+ const userChanged = previousUserId !== newUserId;
883
+ const needsRetry = this._error !== null && !this.isLoadingRef;
884
+ const isEmpty = newUserId !== null && this._organisations.length === 0 && !this.isLoadingRef;
885
+ if (userChanged || needsRetry || isEmpty) {
886
+ if (userChanged) ; else if (needsRetry) {
887
+ logger.debug("OrganisationService", `Previous error detected [ID:${this.instanceId}], retrying initialization`);
888
+ } else if (isEmpty) {
889
+ logger.debug("OrganisationService", `No organisations found [ID:${this.instanceId}], retrying initialization`);
890
+ }
891
+ this._isSuperAdmin = false;
892
+ this.resetInitialization();
893
+ if (userChanged) {
894
+ this._organisations = [];
895
+ this._userMemberships = [];
896
+ this._roleMapState = /* @__PURE__ */ new Map();
897
+ this._selectedOrganisation = null;
898
+ this._isContextReady = false;
899
+ }
900
+ this.lastLoadTimeRef = 0;
901
+ }
902
+ this.user = user;
903
+ this.session = session;
904
+ this.notify();
905
+ }
906
+ // Organisation methods
907
+ async switchOrganisation(orgId) {
908
+ if (!this.validateOrganisationAccess(orgId)) {
909
+ throw new Error(`User does not have access to organisation ${orgId}`);
910
+ }
911
+ const targetOrg = this._organisations.find((org) => org.id === orgId);
912
+ if (!targetOrg) {
913
+ throw new Error(`Organisation ${orgId} not found in user's organisations`);
914
+ }
915
+ this._selectedOrganisation = targetOrg;
916
+ localStorage.setItem("pace-core-selected-organisation", JSON.stringify(targetOrg));
917
+ await this.setDatabaseOrganisationContext(targetOrg);
918
+ this.notify();
919
+ }
920
+ getUserRole(orgId) {
921
+ const targetOrgId = orgId || this._selectedOrganisation?.id;
922
+ if (!targetOrgId) return "no_access";
923
+ return this._roleMapState.get(targetOrgId) || "no_access";
924
+ }
925
+ validateOrganisationAccess(orgId) {
926
+ return this._userMemberships.some(
927
+ (m) => m.organisation_id === orgId && m.status === "active" && m.revoked_at === null
928
+ );
929
+ }
930
+ async refreshOrganisations() {
931
+ if (!this.user || !this.session || !this.supabaseClient) return;
932
+ this._isLoading = true;
933
+ this.notify();
934
+ await this.loadUserOrganisations();
935
+ }
936
+ ensureOrganisationContext() {
937
+ if (!this._selectedOrganisation) {
938
+ throw new Error("Organisation context is required but not available");
939
+ }
940
+ return this._selectedOrganisation;
941
+ }
942
+ isOrganisationSecure() {
943
+ return !!(this._selectedOrganisation && this.user);
944
+ }
945
+ getPrimaryOrganisation() {
946
+ const rolePriority = ["org_admin", "leader", "member"];
947
+ for (const role of rolePriority) {
948
+ const membership = this._userMemberships.find((m) => m.role === role);
949
+ if (membership) {
950
+ return this._organisations.find((org) => org.id === membership.organisation_id) || null;
951
+ }
952
+ }
953
+ return null;
954
+ }
955
+ buildOrganisationHierarchy(orgs) {
956
+ const orgMap = /* @__PURE__ */ new Map();
957
+ orgs.forEach((org) => orgMap.set(org.id, org));
958
+ const roots = [];
959
+ orgs.forEach((org) => {
960
+ if (!org.parent_id) {
961
+ roots.push({
962
+ organisation: org,
963
+ children: [],
964
+ depth: 0
965
+ });
966
+ }
967
+ });
968
+ return roots;
969
+ }
970
+ // Lifecycle methods
971
+ async initialize() {
972
+ if (!this.user) {
973
+ return;
974
+ }
975
+ await super.initialize();
976
+ if (!this.isLoadingRef) {
977
+ await this.loadUserOrganisations();
978
+ }
979
+ }
980
+ cleanup() {
981
+ this.isLoadingRef = false;
982
+ this.hasFailedRef = false;
983
+ this.lastLoadTimeRef = 0;
984
+ if (this.abortControllerRef) {
985
+ this.abortControllerRef = null;
986
+ }
987
+ this._selectedOrganisation = null;
988
+ this._organisations = [];
989
+ this._userMemberships = [];
990
+ this._roleMapState = /* @__PURE__ */ new Map();
991
+ this._isLoading = false;
992
+ this._error = null;
993
+ this._isContextReady = false;
994
+ super.cleanup();
995
+ }
996
+ async doInitialize() {
997
+ }
998
+ doCleanup() {
999
+ }
1000
+ async setDatabaseOrganisationContext(_organisation) {
1001
+ this._isContextReady = true;
1002
+ this.notify();
1003
+ }
1004
+ /** Returns false if load should return early; when true, abort controller and loading state are set. */
1005
+ prepareLoad() {
1006
+ if (!this.user || !this.session || !this.supabaseClient) {
1007
+ this._selectedOrganisation = null;
1008
+ this._organisations = [];
1009
+ this._userMemberships = [];
1010
+ this._isLoading = false;
1011
+ this._error = null;
1012
+ this.notify();
1013
+ return false;
1014
+ }
1015
+ if (this.isLoadingRef) {
1016
+ this._isLoading = true;
1017
+ this.notify();
1018
+ return false;
1019
+ }
1020
+ const now = Date.now();
1021
+ if (this._organisations.length > 0 && now - this.lastLoadTimeRef < 2e3) {
1022
+ if (this._organisations.length > 0 || this._selectedOrganisation) {
1023
+ this._isLoading = false;
1024
+ } else {
1025
+ this._isLoading = true;
1026
+ }
1027
+ this.notify();
1028
+ return false;
1029
+ }
1030
+ if (this.abortControllerRef) {
1031
+ this.abortControllerRef.abort();
1032
+ }
1033
+ this.abortControllerRef = new AbortController();
1034
+ this.lastLoadTimeRef = now;
1035
+ this.isLoadingRef = true;
1036
+ this._isLoading = true;
1037
+ this._error = null;
1038
+ this.notify();
1039
+ return true;
1040
+ }
1041
+ async fetchRolesAndOrganisations(signal) {
1042
+ if (signal.aborted) {
1043
+ throw new Error("Request aborted");
1044
+ }
1045
+ if (!this.supabaseClient || !this.user) {
1046
+ throw new Error("Missing supabase client or user");
1047
+ }
1048
+ try {
1049
+ const { data: rolesData, error: rolesError } = await this.supabaseClient.from("rbac_organisation_roles").select(`
1050
+ id,
1051
+ user_id,
1052
+ organisation_id,
1053
+ role,
1054
+ status,
1055
+ granted_at,
1056
+ granted_by,
1057
+ revoked_at,
1058
+ revoked_by,
1059
+ notes,
1060
+ created_at,
1061
+ updated_at,
1062
+ core_organisations!inner(
1063
+ id,
1064
+ name,
1065
+ display_name,
1066
+ subscription_tier,
1067
+ settings,
1068
+ is_active,
1069
+ parent_id,
1070
+ created_at,
1071
+ updated_at
1072
+ )
1073
+ `).eq("user_id", this.user.id).eq("status", "active").is("revoked_at", null);
1074
+ if (rolesError) {
1075
+ logger.error("OrganisationService", "Error loading organisation roles:", rolesError);
1076
+ throw rolesError;
1077
+ }
1078
+ const memberships = rolesData?.map((m) => ({
1079
+ ...m,
1080
+ user_id: assertUserId(m.user_id),
1081
+ organisation_id: assertOrganisationId(m.organisation_id)
1082
+ })) || [];
1083
+ const organisationsMap = /* @__PURE__ */ new Map();
1084
+ rolesData?.forEach((role) => {
1085
+ const roleWithOrg = role;
1086
+ const orgData = roleWithOrg.core_organisations;
1087
+ if (orgData && roleWithOrg.organisation_id && !organisationsMap.has(roleWithOrg.organisation_id)) {
1088
+ organisationsMap.set(roleWithOrg.organisation_id, {
1089
+ id: orgData.id,
1090
+ name: orgData.name,
1091
+ display_name: orgData.display_name,
1092
+ subscription_tier: orgData.subscription_tier,
1093
+ settings: orgData.settings,
1094
+ is_active: orgData.is_active,
1095
+ parent_id: orgData.parent_id,
1096
+ created_at: orgData.created_at,
1097
+ updated_at: orgData.updated_at
1098
+ });
1099
+ }
1100
+ });
1101
+ const organisations = Array.from(organisationsMap.values());
1102
+ return { memberships, organisations };
1103
+ } catch (queryError) {
1104
+ const err2 = queryError instanceof Error ? queryError : queryError && typeof queryError === "object" && "message" in queryError ? new Error(String(queryError.message)) : new Error(String(queryError));
1105
+ logger.error("OrganisationService", "Error loading organisation roles:", err2);
1106
+ throw err2;
1107
+ }
1108
+ }
1109
+ async checkAndCacheSuperAdmin() {
1110
+ if (!this.user?.id) {
1111
+ this._isSuperAdmin = false;
1112
+ return false;
1113
+ }
1114
+ try {
1115
+ const { isSuperAdmin: checkSuperAdmin, isRBACInitialized: isRBACInitialized2, setupRBAC: setupRBAC2 } = await import('./api-6OQXYT67.js');
1116
+ if (!isRBACInitialized2() && this.supabaseClient) {
1117
+ setupRBAC2(this.supabaseClient);
1118
+ }
1119
+ if (isRBACInitialized2()) {
1120
+ const result = await checkSuperAdmin(this.user.id);
1121
+ const isSuper = result.ok && result.data;
1122
+ this._isSuperAdmin = isSuper;
1123
+ return isSuper;
1124
+ }
1125
+ this._isSuperAdmin = false;
1126
+ return false;
1127
+ } catch (error) {
1128
+ logger.warn("OrganisationService", "Failed to check super admin status", { error });
1129
+ this._isSuperAdmin = false;
1130
+ return false;
1131
+ }
1132
+ }
1133
+ applyEmptyStateAndNotify() {
1134
+ this._organisations = [];
1135
+ this._userMemberships = [];
1136
+ this._isLoading = false;
1137
+ this._error = null;
1138
+ this._isContextReady = true;
1139
+ this.notify();
1140
+ }
1141
+ selectInitialOrganisation(activeOrgs, memberships, organisations) {
1142
+ let initialOrg = null;
1143
+ try {
1144
+ const persistedOrgString = localStorage.getItem("pace-core-selected-organisation");
1145
+ if (persistedOrgString) {
1146
+ const persistedOrg = JSON.parse(persistedOrgString);
1147
+ if (persistedOrg.id && typeof persistedOrg.id === "string" && persistedOrg.id.trim() !== "") {
1148
+ const validPersistedOrg = activeOrgs.find((org) => org.id === persistedOrg.id);
1149
+ if (validPersistedOrg) {
1150
+ initialOrg = validPersistedOrg;
1151
+ } else {
1152
+ localStorage.removeItem("pace-core-selected-organisation");
1153
+ }
1154
+ } else {
1155
+ localStorage.removeItem("pace-core-selected-organisation");
1156
+ }
1157
+ }
1158
+ } catch {
1159
+ localStorage.removeItem("pace-core-selected-organisation");
1160
+ }
1161
+ if (!initialOrg) {
1162
+ const adminMembership = memberships.find((m) => m.role === "org_admin");
1163
+ if (adminMembership) {
1164
+ const foundOrg = organisations.find((org) => org.id === adminMembership.organisation_id);
1165
+ if (foundOrg) initialOrg = foundOrg;
1166
+ }
1167
+ }
1168
+ if (!initialOrg) {
1169
+ initialOrg = activeOrgs[0];
1170
+ }
1171
+ if (!initialOrg) {
1172
+ throw new Error("No valid organisation found for user");
1173
+ }
1174
+ localStorage.setItem("pace-core-selected-organisation", JSON.stringify(initialOrg));
1175
+ return initialOrg;
1176
+ }
1177
+ async loadUserOrganisations() {
1178
+ if (!this.prepareLoad()) return;
1179
+ const abortSignal = this.abortControllerRef.signal;
1180
+ try {
1181
+ const { memberships, organisations } = await this.fetchRolesAndOrganisations(abortSignal);
1182
+ const userIsSuperAdmin = await this.checkAndCacheSuperAdmin();
1183
+ if (!memberships || memberships.length === 0) {
1184
+ if (userIsSuperAdmin) {
1185
+ this.applyEmptyStateAndNotify();
1186
+ return;
1187
+ }
1188
+ throw new Error("User has no active organisation memberships");
1189
+ }
1190
+ if (!organisations || organisations.length === 0) {
1191
+ if (userIsSuperAdmin) {
1192
+ this.applyEmptyStateAndNotify();
1193
+ return;
1194
+ }
1195
+ throw new Error("No organisations found in role data");
1196
+ }
1197
+ const roleMap = /* @__PURE__ */ new Map();
1198
+ memberships.forEach((membership) => {
1199
+ roleMap.set(membership.organisation_id, membership.role);
1200
+ });
1201
+ const activeOrgs = organisations.filter((org) => org.is_active);
1202
+ if (activeOrgs.length === 0) {
1203
+ if (userIsSuperAdmin) {
1204
+ this.applyEmptyStateAndNotify();
1205
+ return;
1206
+ }
1207
+ throw new Error("User has no access to active organisations");
1208
+ }
1209
+ const sortedOrgs = [...activeOrgs].sort((a, b) => {
1210
+ const nameA = (a.display_name || a.name || "").toLowerCase();
1211
+ const nameB = (b.display_name || b.name || "").toLowerCase();
1212
+ return nameA.localeCompare(nameB);
1213
+ });
1214
+ this._organisations = sortedOrgs;
1215
+ this._userMemberships = memberships;
1216
+ this._roleMapState = roleMap;
1217
+ const initialOrg = this.selectInitialOrganisation(activeOrgs, memberships, organisations);
1218
+ const currentSelectedOrg = this._selectedOrganisation;
1219
+ if (currentSelectedOrg && !activeOrgs.some((org) => org.id === currentSelectedOrg.id)) {
1220
+ logger.warn("OrganisationService", "Current selected organisation is no longer valid, resetting", {
1221
+ invalidOrgId: currentSelectedOrg.id,
1222
+ validOrgIds: activeOrgs.map((o) => o.id)
1223
+ });
1224
+ this._selectedOrganisation = null;
1225
+ }
1226
+ this._selectedOrganisation = initialOrg;
1227
+ await this.setDatabaseOrganisationContext(initialOrg);
1228
+ this.retryCount = 0;
1229
+ this.hasFailedRef = false;
1230
+ } catch (err2) {
1231
+ const error = err2;
1232
+ if (error.message !== "User has no access to active organisations") {
1233
+ logger.error("OrganisationService", "Failed to load organisations:", err2);
1234
+ }
1235
+ this._error = error;
1236
+ this.retryCount = this.retryCount + 1;
1237
+ this.hasFailedRef = true;
1238
+ this.clearAllCachedData();
1239
+ this._isContextReady = true;
1240
+ } finally {
1241
+ this.isLoadingRef = false;
1242
+ this._isLoading = false;
1243
+ this.abortControllerRef = null;
1244
+ this.notify();
1245
+ }
1246
+ }
1247
+ clearAllCachedData() {
1248
+ localStorage.removeItem("pace-core-selected-organisation");
1249
+ localStorage.removeItem("pace-core-organisation-context");
1250
+ this._selectedOrganisation = null;
1251
+ this._organisations = [];
1252
+ this._userMemberships = [];
1253
+ this._roleMapState = /* @__PURE__ */ new Map();
1254
+ this.retryCount = 0;
1255
+ this._isContextReady = false;
1256
+ }
1257
+ };
1258
+ _OrganisationService.instanceCount = 0;
1259
+ var OrganisationService = _OrganisationService;
1260
+ function OrganisationServiceProvider({
1261
+ children,
1262
+ supabaseClient,
1263
+ user,
1264
+ session
1265
+ }) {
1266
+ const organisationServiceRef = useRef(null);
1267
+ if (!organisationServiceRef.current) {
1268
+ organisationServiceRef.current = new OrganisationService(supabaseClient, user, session);
1269
+ }
1270
+ const organisationService = organisationServiceRef.current;
1271
+ useEffect(() => {
1272
+ organisationService.updateDependencies(user, session);
1273
+ let isMounted = true;
1274
+ organisationService.initialize().catch((error) => {
1275
+ if (isMounted) {
1276
+ const errorMessage = error instanceof Error ? error.message : String(error);
1277
+ if (errorMessage === "User has no access to active organisations") {
1278
+ logger.warn("OrganisationServiceProvider", "User has no active organisations (this is expected for users without organisation access):", error);
1279
+ } else {
1280
+ logger.error("OrganisationServiceProvider", "Failed to initialize organisation service:", error);
1281
+ }
1282
+ }
1283
+ });
1284
+ return () => {
1285
+ isMounted = false;
1286
+ };
1287
+ }, [organisationService, user, session]);
1288
+ useEffect(() => {
1289
+ return () => {
1290
+ organisationService.cleanup();
1291
+ };
1292
+ }, [organisationService]);
1293
+ const contextValue = useMemo(() => ({
1294
+ organisationService
1295
+ }), [organisationService]);
1296
+ return /* @__PURE__ */ jsx(OrganisationServiceContext.Provider, { value: contextValue, children });
1297
+ }
1298
+
1299
+ // src/services/EventService.ts
1300
+ var _EventService = class _EventService extends BaseService {
1301
+ constructor(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
1302
+ super();
1303
+ this.events = [];
1304
+ this.selectedEvent = null;
1305
+ this._isLoading = false;
1306
+ // Start as false to avoid blocking UI
1307
+ this.error = null;
1308
+ // Dependencies
1309
+ this.supabaseClient = null;
1310
+ this.user = null;
1311
+ this.session = null;
1312
+ this.appName = "";
1313
+ this.selectedOrganisation = null;
1314
+ this.setSelectedEventId = null;
1315
+ this.isSuperAdmin = false;
1316
+ // Track super admin status for conditional validation
1317
+ // App config removed - scope is now page-level only (rbac_app_pages.scope_type)
1318
+ // Internal state management
1319
+ this.isInitializedRef = false;
1320
+ this.isFetchingRef = false;
1321
+ this.hasAutoSelectedRef = false;
1322
+ this.userClearedEventRef = false;
1323
+ this.instanceId = ++_EventService.instanceCount;
1324
+ this.supabaseClient = supabaseClient;
1325
+ this.user = user;
1326
+ this.session = session;
1327
+ this.appName = appName;
1328
+ this.selectedOrganisation = selectedOrganisation;
1329
+ this.setSelectedEventId = setSelectedEventId;
1330
+ }
1331
+ getInstanceId() {
1332
+ return this.instanceId;
1333
+ }
1334
+ // Helper method to get user-scoped storage key
1335
+ getStorageKey(userId) {
1336
+ if (!userId) {
1337
+ return "pace-core-selected-event-no-user";
1338
+ }
1339
+ return `pace-core-selected-event-${userId}`;
1340
+ }
1341
+ // Update dependencies
1342
+ async updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
1343
+ const previousOrgId = this.selectedOrganisation?.id;
1344
+ const newOrgId = selectedOrganisation?.id;
1345
+ const previousUserId = this.user?.id || null;
1346
+ const newUserId = user?.id || null;
1347
+ await this.handleUserChange(previousUserId, newUserId);
1348
+ this.applyNewDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
1349
+ await this.updateSuperAdminStatus(user);
1350
+ this.handleOrganisationChange(previousOrgId, newOrgId);
1351
+ this.notify();
1352
+ }
1353
+ async handleUserChange(previousUserId, newUserId) {
1354
+ if (previousUserId === newUserId) {
1355
+ return;
1356
+ }
1357
+ if (previousUserId !== null) {
1358
+ await this.clearEventSelectionForUser(previousUserId);
1359
+ }
1360
+ if (newUserId === null) {
1361
+ this.selectedEvent = null;
1362
+ this.setSelectedEventId?.(null);
1363
+ }
1364
+ this.resetInitialization();
1365
+ this.isInitializedRef = false;
1366
+ this.isFetchingRef = false;
1367
+ this.userClearedEventRef = false;
1368
+ this.hasAutoSelectedRef = false;
1369
+ }
1370
+ applyNewDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId) {
1371
+ this.supabaseClient = supabaseClient;
1372
+ this.user = user;
1373
+ this.session = session;
1374
+ this.appName = appName;
1375
+ this.selectedOrganisation = selectedOrganisation;
1376
+ this.setSelectedEventId = setSelectedEventId;
1377
+ }
1378
+ async updateSuperAdminStatus(user) {
1379
+ if (!user?.id) {
1380
+ this.isSuperAdmin = false;
1381
+ return;
1382
+ }
1383
+ try {
1384
+ const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-6OQXYT67.js');
1385
+ if (!isRBACInitialized2() && this.supabaseClient) {
1386
+ setupRBAC2(this.supabaseClient);
1387
+ }
1388
+ if (isRBACInitialized2()) {
1389
+ const result = await checkSuperAdmin(user.id);
1390
+ this.isSuperAdmin = result.ok && result.data;
1391
+ } else {
1392
+ logger.warn("EventService", "RBAC not initialized in updateDependencies, keeping existing super admin status", {
1393
+ userId: user.id,
1394
+ existingIsSuperAdmin: this.isSuperAdmin,
1395
+ note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1396
+ });
1397
+ }
1398
+ } catch (error) {
1399
+ logger.warn("EventService", "Failed to check super admin status in updateDependencies", {
1400
+ error,
1401
+ userId: user.id,
1402
+ existingIsSuperAdmin: this.isSuperAdmin
1403
+ });
1404
+ }
1405
+ }
1406
+ handleOrganisationChange(previousOrgId, newOrgId) {
1407
+ if (previousOrgId === newOrgId) {
1408
+ return;
1409
+ }
1410
+ this.resetInitialization();
1411
+ this.isInitializedRef = false;
1412
+ this.isFetchingRef = false;
1413
+ const shouldClearEvents = !this.isSuperAdmin;
1414
+ const isFirstOrgSet = (previousOrgId === null || previousOrgId === void 0) && newOrgId !== null && newOrgId !== void 0;
1415
+ if (isFirstOrgSet) {
1416
+ const hadAutoSelectedEvent = this.hasAutoSelectedRef && !!this.selectedEvent;
1417
+ this.userClearedEventRef = false;
1418
+ if (!hadAutoSelectedEvent) {
1419
+ this.hasAutoSelectedRef = false;
1420
+ }
1421
+ logger.debug("EventService", "Organisation first set - preserving event and resetting auto-selection flags", {
1422
+ organisationId: newOrgId,
1423
+ hasSelectedEvent: !!this.selectedEvent,
1424
+ selectedEventId: this.selectedEvent?.event_id,
1425
+ hadAutoSelectedEvent,
1426
+ preservingEvent: hadAutoSelectedEvent,
1427
+ previousOrgId,
1428
+ newOrgId
1429
+ });
1430
+ return;
1431
+ }
1432
+ const switchingOrgs = previousOrgId != null && newOrgId != null && previousOrgId !== newOrgId;
1433
+ const orgRemoved = previousOrgId != null && newOrgId === null;
1434
+ if (switchingOrgs && shouldClearEvents) {
1435
+ this.events = [];
1436
+ this.setSelectedEvent(null);
1437
+ } else if (orgRemoved && shouldClearEvents) {
1438
+ this.events = [];
1439
+ this.setSelectedEvent(null);
1440
+ }
1441
+ }
1442
+ // Event state getters
1443
+ getEvents() {
1444
+ return this.events;
1445
+ }
1446
+ getSelectedEvent() {
1447
+ return this.selectedEvent;
1448
+ }
1449
+ isLoading() {
1450
+ return this._isLoading;
1451
+ }
1452
+ getError() {
1453
+ return this.error;
1454
+ }
1455
+ // Event methods
1456
+ setSelectedEvent(event) {
1457
+ if (event) {
1458
+ const orgId = event.organisation_id;
1459
+ const missingOrg = !orgId || typeof orgId === "string" && orgId.trim() === "";
1460
+ const eventToStore = missingOrg && this.selectedOrganisation?.id ? { ...event, organisation_id: this.selectedOrganisation.id } : event;
1461
+ this.selectedEvent = eventToStore;
1462
+ this.setSelectedEventId?.(event.event_id);
1463
+ this.persistEventSelection(event.event_id).catch((error) => {
1464
+ logger.warn("EventService", "Failed to persist event selection:", error);
1465
+ });
1466
+ this.userClearedEventRef = false;
1467
+ } else {
1468
+ this.selectedEvent?.event_id;
1469
+ this.selectedEvent = null;
1470
+ this.setSelectedEventId?.(null);
1471
+ this.clearEventSelection().catch((error) => {
1472
+ logger.warn("EventService", "Failed to clear event selection:", error);
1473
+ });
1474
+ this.hasAutoSelectedRef = false;
1475
+ this.userClearedEventRef = true;
1476
+ }
1477
+ this.notify();
1478
+ }
1479
+ async refreshEvents() {
1480
+ this.isInitializedRef = false;
1481
+ this.isFetchingRef = false;
1482
+ await this.fetchEvents();
1483
+ }
1484
+ async loadPersistedEvent(events) {
1485
+ try {
1486
+ const userId = this.user?.id || null;
1487
+ if (!userId) {
1488
+ return false;
1489
+ }
1490
+ const storageKey = this.getStorageKey(userId);
1491
+ const persistedEventId = await secureStorage.getItem(storageKey);
1492
+ if (persistedEventId && events.length > 0) {
1493
+ const persistedEvent = events.find((event) => event.event_id === persistedEventId);
1494
+ if (persistedEvent) {
1495
+ this.setSelectedEvent(persistedEvent);
1496
+ return true;
1497
+ } else {
1498
+ await secureStorage.removeItem(storageKey);
1499
+ }
1500
+ }
1501
+ } catch (error) {
1502
+ logger.warn("EventService", "Failed to load persisted event:", error);
1503
+ }
1504
+ return false;
1505
+ }
1506
+ /**
1507
+ * Restore persisted event after login screen has rendered
1508
+ * This should be called explicitly from login page component
1509
+ *
1510
+ * @returns Promise<boolean> - true if event was successfully restored, false otherwise
1511
+ */
1512
+ async restorePersistedEvent() {
1513
+ if (this.events.length === 0) {
1514
+ return false;
1515
+ }
1516
+ return await this.loadPersistedEvent(this.events);
1517
+ }
1518
+ async persistEventSelection(eventId) {
1519
+ try {
1520
+ const userId = this.user?.id || null;
1521
+ const storageKey = this.getStorageKey(userId);
1522
+ await secureStorage.setItem(storageKey, eventId, { encrypt: true });
1523
+ } catch (error) {
1524
+ logger.warn("EventService", "Failed to persist event selection:", error);
1525
+ }
1526
+ }
1527
+ async clearEventSelection() {
1528
+ try {
1529
+ const userId = this.user?.id || null;
1530
+ const storageKey = this.getStorageKey(userId);
1531
+ await secureStorage.removeItem(storageKey);
1532
+ this.selectedEvent = null;
1533
+ this.setSelectedEventId?.(null);
1534
+ } catch (error) {
1535
+ logger.warn("EventService", "Failed to clear event selection:", error);
1536
+ }
1537
+ }
1538
+ /**
1539
+ * Clear event selection for a specific user (used when user logs out or changes)
1540
+ */
1541
+ async clearEventSelectionForUser(userId) {
1542
+ try {
1543
+ if (!userId) return;
1544
+ const storageKey = this.getStorageKey(userId);
1545
+ await secureStorage.removeItem(storageKey);
1546
+ } catch (error) {
1547
+ logger.warn("EventService", "Failed to clear event selection for user:", error);
1548
+ }
1549
+ }
1550
+ autoSelectNextEvent(events) {
1551
+ const nextEvent = this.getNextEventByDate(events);
1552
+ if (nextEvent) {
1553
+ this.setSelectedEvent(nextEvent);
1554
+ }
1555
+ }
1556
+ // Lifecycle methods
1557
+ async initialize() {
1558
+ await super.initialize();
1559
+ }
1560
+ cleanup() {
1561
+ super.cleanup();
1562
+ }
1563
+ async doInitialize() {
1564
+ if (this.isInitializedRef) {
1565
+ return;
1566
+ }
1567
+ if (this.isFetchingRef) {
1568
+ return;
1569
+ }
1570
+ try {
1571
+ sessionStorage.removeItem("pace-core-selected-event");
1572
+ localStorage.removeItem("pace-core-selected-event");
1573
+ localStorage.removeItem("_sec_pace-core-selected-event");
1574
+ } catch (error) {
1575
+ logger.warn("EventService", "Failed to clean up old storage keys:", error);
1576
+ }
1577
+ if (!this.user) {
1578
+ return;
1579
+ }
1580
+ await this.fetchEvents(false);
1581
+ this.isInitializedRef = true;
1582
+ }
1583
+ doCleanup() {
1584
+ }
1585
+ async resolveOrganisationIdForRpc() {
1586
+ let userIsSuperAdmin = this.isSuperAdmin;
1587
+ try {
1588
+ const { isRBACInitialized: isRBACInitialized2, isSuperAdmin: checkSuperAdmin, setupRBAC: setupRBAC2 } = await import('./api-6OQXYT67.js');
1589
+ if (!isRBACInitialized2() && this.supabaseClient) {
1590
+ setupRBAC2(this.supabaseClient);
1591
+ }
1592
+ if (isRBACInitialized2()) {
1593
+ const result = await checkSuperAdmin(this.user.id);
1594
+ userIsSuperAdmin = result.ok && result.data;
1595
+ this.isSuperAdmin = userIsSuperAdmin;
1596
+ } else {
1597
+ if (this.isSuperAdmin) {
1598
+ userIsSuperAdmin = true;
1599
+ logger.warn("EventService", "RBAC not initialized, using cached super admin status", {
1600
+ userId: this.user.id,
1601
+ cachedIsSuperAdmin: this.isSuperAdmin,
1602
+ note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1603
+ });
1604
+ } else {
1605
+ logger.warn("EventService", "RBAC not initialized, using cached non-super-admin status", {
1606
+ userId: this.user.id,
1607
+ cachedIsSuperAdmin: this.isSuperAdmin,
1608
+ note: "RBAC should be initialized by UnifiedAuthProvider. This may indicate EventService is being used outside the provider."
1609
+ });
1610
+ }
1611
+ }
1612
+ if (userIsSuperAdmin) {
1613
+ return null;
1614
+ }
1615
+ if (this.selectedEvent) {
1616
+ return this.selectedEvent.organisation_id;
1617
+ }
1618
+ if (this.selectedOrganisation) {
1619
+ return this.selectedOrganisation.id;
1620
+ }
1621
+ return null;
1622
+ } catch (superAdminCheckError) {
1623
+ if (this.isSuperAdmin) {
1624
+ logger.warn("EventService", "Super admin check failed, using cached super admin status", {
1625
+ error: superAdminCheckError,
1626
+ cachedIsSuperAdmin: this.isSuperAdmin
1627
+ });
1628
+ return null;
1629
+ }
1630
+ logger.warn("EventService", "Failed to check super admin status, using organisation-scoped query", {
1631
+ error: superAdminCheckError,
1632
+ cachedIsSuperAdmin: this.isSuperAdmin
1633
+ });
1634
+ if (this.selectedEvent) {
1635
+ return this.selectedEvent.organisation_id;
1636
+ }
1637
+ if (this.selectedOrganisation) {
1638
+ return this.selectedOrganisation.id;
1639
+ }
1640
+ return null;
1641
+ }
1642
+ }
1643
+ transformRpcDataToEvents(data) {
1644
+ const eventsData = Array.isArray(data) ? data : [];
1645
+ const transformed = eventsData.map((event) => ({
1646
+ id: event.event_id,
1647
+ event_id: event.event_id,
1648
+ event_name: event.event_name,
1649
+ event_code: event.event_code,
1650
+ event_date: event.event_date ?? void 0,
1651
+ event_venue: event.event_venue ?? void 0,
1652
+ event_participants: event.event_participants ?? void 0,
1653
+ event_colours: event.event_colours,
1654
+ event_logo: "",
1655
+ organisation_id: assertOrganisationId(event.organisation_id),
1656
+ is_visible: event.is_visible,
1657
+ created_at: (/* @__PURE__ */ new Date()).toISOString(),
1658
+ updated_at: (/* @__PURE__ */ new Date()).toISOString()
1659
+ }));
1660
+ return [...transformed].sort((a, b) => {
1661
+ if (a.event_date && b.event_date) {
1662
+ return new Date(b.event_date).getTime() - new Date(a.event_date).getTime();
1663
+ }
1664
+ if (a.event_date && !b.event_date) return -1;
1665
+ if (!a.event_date && b.event_date) return 1;
1666
+ return 0;
1667
+ });
1668
+ }
1669
+ validateSelectedEventInList(events) {
1670
+ if (!this.selectedEvent) {
1671
+ return;
1672
+ }
1673
+ const selectedEventId = this.selectedEvent.event_id;
1674
+ const eventStillExists = events.some((e) => e.event_id === selectedEventId);
1675
+ if (!eventStillExists) {
1676
+ const previousUserClearedRef = this.userClearedEventRef;
1677
+ this.selectedEvent = null;
1678
+ this.setSelectedEventId?.(null);
1679
+ this.userClearedEventRef = previousUserClearedRef;
1680
+ }
1681
+ }
1682
+ async runPersistedOrAutoSelection(events, skipLoadPersisted) {
1683
+ this.hasAutoSelectedRef = false;
1684
+ if (!skipLoadPersisted) {
1685
+ const persistedEventLoaded = await this.loadPersistedEvent(events);
1686
+ if (!persistedEventLoaded && !this.userClearedEventRef) {
1687
+ const nextEvent = this.getNextEventByDate(events);
1688
+ if (nextEvent) {
1689
+ this.hasAutoSelectedRef = true;
1690
+ this.setSelectedEvent(nextEvent);
1691
+ }
1692
+ }
1693
+ } else if (!this.userClearedEventRef) {
1694
+ const nextEvent = this.getNextEventByDate(events);
1695
+ if (nextEvent) {
1696
+ this.hasAutoSelectedRef = true;
1697
+ this.setSelectedEvent(nextEvent);
1698
+ }
1699
+ }
1700
+ }
1701
+ async fetchEvents(skipLoadPersisted = false) {
1702
+ if (!this.user || !this.session || !this.supabaseClient || !this.appName) {
1703
+ this.notify();
1704
+ return;
1705
+ }
1706
+ this._isLoading = true;
1707
+ this.notify();
1708
+ if (this.isFetchingRef) {
1709
+ return;
1710
+ }
1711
+ this.isFetchingRef = true;
1712
+ const isMounted = true;
1713
+ try {
1714
+ const organisationIdForRpc = await this.resolveOrganisationIdForRpc();
1715
+ const { data, error: rpcError } = await this.supabaseClient.rpc("data_user_events_get", {
1716
+ p_user_id: this.user.id,
1717
+ p_organisation_id: organisationIdForRpc,
1718
+ p_app_name: this.appName
1719
+ });
1720
+ if (rpcError) {
1721
+ logger.error("EventService", "RPC error fetching events:", rpcError);
1722
+ throw new Error(rpcError.message || "Failed to fetch events");
1723
+ }
1724
+ if (isMounted) {
1725
+ const transformedEvents = this.transformRpcDataToEvents(data ?? []);
1726
+ this.events = transformedEvents;
1727
+ this.error = null;
1728
+ this.validateSelectedEventInList(transformedEvents);
1729
+ await this.runPersistedOrAutoSelection(transformedEvents, skipLoadPersisted);
1730
+ }
1731
+ } catch (err2) {
1732
+ logger.error("EventService", "Error fetching events:", err2);
1733
+ const _error = err2 instanceof Error ? err2 : new Error("Unknown error occurred");
1734
+ {
1735
+ this.error = _error;
1736
+ this.events = [];
1737
+ }
1738
+ } finally {
1739
+ {
1740
+ this._isLoading = false;
1741
+ }
1742
+ this.isFetchingRef = false;
1743
+ this.notify();
1744
+ }
1745
+ }
1746
+ getNextEventByDate(events) {
1747
+ const eventsToUse = events || this.events;
1748
+ if (!eventsToUse || eventsToUse.length === 0) {
1749
+ return null;
1750
+ }
1751
+ const now = /* @__PURE__ */ new Date();
1752
+ const startOfToday = new Date(now.getFullYear(), now.getMonth(), now.getDate()).getTime();
1753
+ const futureEvents = eventsToUse.filter((event) => {
1754
+ if (!event.event_date) return false;
1755
+ const eventDate = new Date(event.event_date);
1756
+ const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();
1757
+ return startOfEventDate >= startOfToday;
1758
+ });
1759
+ if (futureEvents.length > 0) {
1760
+ const sortedFutureEvents = futureEvents.sort((a, b) => {
1761
+ const dateA = new Date(a.event_date);
1762
+ const dateB = new Date(b.event_date);
1763
+ return dateA.getTime() - dateB.getTime();
1764
+ });
1765
+ return sortedFutureEvents[0];
1766
+ }
1767
+ const pastEvents = eventsToUse.filter((event) => {
1768
+ if (!event.event_date) return false;
1769
+ const eventDate = new Date(event.event_date);
1770
+ const startOfEventDate = new Date(eventDate.getFullYear(), eventDate.getMonth(), eventDate.getDate()).getTime();
1771
+ return startOfEventDate < startOfToday;
1772
+ });
1773
+ if (pastEvents.length > 0) {
1774
+ const sortedPastEvents = pastEvents.sort((a, b) => {
1775
+ const dateA = new Date(a.event_date);
1776
+ const dateB = new Date(b.event_date);
1777
+ return dateB.getTime() - dateA.getTime();
1778
+ });
1779
+ return sortedPastEvents[0];
1780
+ }
1781
+ return null;
1782
+ }
1783
+ };
1784
+ _EventService.instanceCount = 0;
1785
+ var EventService = _EventService;
1786
+ var EventServiceContext = createContext(null);
1787
+ function EventServiceProvider({
1788
+ children,
1789
+ supabaseClient,
1790
+ user,
1791
+ session,
1792
+ appName,
1793
+ selectedOrganisation,
1794
+ setSelectedEventId
1795
+ }) {
1796
+ const eventServiceRef = useRef(null);
1797
+ const initializingRef = useRef(false);
1798
+ if (!eventServiceRef.current) {
1799
+ eventServiceRef.current = new EventService(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId);
1800
+ }
1801
+ const eventService = eventServiceRef.current;
1802
+ useEffect(() => {
1803
+ let isMounted = true;
1804
+ if (initializingRef.current) {
1805
+ return;
1806
+ }
1807
+ const updateAndInitialize = async () => {
1808
+ initializingRef.current = true;
1809
+ try {
1810
+ await eventService.updateDependencies(supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId).catch((error) => {
1811
+ if (isMounted) {
1812
+ logger.error("EventServiceProvider", "Failed to update event service dependencies:", error);
1813
+ }
1814
+ return;
1815
+ });
1816
+ if (!isMounted) return;
1817
+ if (user && session && supabaseClient && appName) {
1818
+ await eventService.initialize().catch((error) => {
1819
+ if (isMounted) {
1820
+ logger.error("EventServiceProvider", "Failed to initialize event service:", error);
1821
+ }
1822
+ });
1823
+ } else {
1824
+ }
1825
+ } finally {
1826
+ initializingRef.current = false;
1827
+ }
1828
+ };
1829
+ updateAndInitialize();
1830
+ return () => {
1831
+ isMounted = false;
1832
+ initializingRef.current = false;
1833
+ };
1834
+ }, [supabaseClient, user, session, appName, selectedOrganisation, setSelectedEventId, eventService]);
1835
+ useEffect(() => {
1836
+ return () => {
1837
+ eventService.cleanup();
1838
+ };
1839
+ }, [eventService]);
1840
+ const contextValue = useMemo(() => ({
1841
+ eventService
1842
+ }), [eventService]);
1843
+ return /* @__PURE__ */ jsx(EventServiceContext.Provider, { value: contextValue, children });
1844
+ }
1845
+ var InactivityServiceContext = createContext(null);
1846
+
1847
+ // src/services/InactivityService.ts
1848
+ var InactivityService = class extends BaseService {
1849
+ constructor(supabaseClient, user, session, idleTimeoutMs = 30 * 60 * 1e3, warnBeforeMs = 60 * 1e3, onIdleLogout) {
1850
+ super();
1851
+ this._showInactivityWarning = false;
1852
+ this._inactivityTimeRemaining = 0;
1853
+ this._isIdle = false;
1854
+ this._timeRemaining = 0;
1855
+ this._showWarning = false;
1856
+ this._isTracking = false;
1857
+ // Dependencies
1858
+ this.supabaseClient = null;
1859
+ this.user = null;
1860
+ this.session = null;
1861
+ this.idleTimeoutMs = 30 * 60 * 1e3;
1862
+ // 30 minutes
1863
+ this.warnBeforeMs = 60 * 1e3;
1864
+ // 60 seconds
1865
+ this.onIdleLogout = null;
1866
+ // Internal state management
1867
+ this.inactivityTracker = null;
1868
+ this.isInactivityEnabled = true;
1869
+ this.cleanupHandlers = null;
1870
+ this.supabaseClient = supabaseClient;
1871
+ this.user = user;
1872
+ this.session = session;
1873
+ this.idleTimeoutMs = idleTimeoutMs;
1874
+ this.warnBeforeMs = warnBeforeMs;
1875
+ this.onIdleLogout = onIdleLogout;
1876
+ this._timeRemaining = idleTimeoutMs;
1877
+ }
1878
+ // Interface implementation
1879
+ isIdle() {
1880
+ return this._isIdle;
1881
+ }
1882
+ getTimeRemaining() {
1883
+ return this._timeRemaining;
1884
+ }
1885
+ isWarningShown() {
1886
+ return this._showWarning;
1887
+ }
1888
+ isTracking() {
1889
+ return this._isTracking;
1890
+ }
1891
+ getShowInactivityWarning() {
1892
+ return this._showInactivityWarning;
1893
+ }
1894
+ getInactivityTimeRemaining() {
1895
+ return this._inactivityTimeRemaining;
1896
+ }
1897
+ // Additional getter methods that tests expect
1898
+ getIsIdle() {
1899
+ return this._isIdle;
1900
+ }
1901
+ getIsTracking() {
1902
+ return this._isTracking;
1903
+ }
1904
+ getShowWarning() {
1905
+ return this._showWarning;
1906
+ }
1907
+ // Additional methods for testing
1908
+ setShowInactivityWarning(value) {
1909
+ this._showInactivityWarning = value;
1910
+ this.notify();
1911
+ }
1912
+ setInactivityTimeRemaining(value) {
1913
+ this._inactivityTimeRemaining = value;
1914
+ this.notify();
1915
+ }
1916
+ setIsIdle(value) {
1917
+ this._isIdle = value;
1918
+ this.notify();
1919
+ }
1920
+ setTimeRemaining(value) {
1921
+ this._timeRemaining = value;
1922
+ this.notify();
1923
+ }
1924
+ setShowWarning(value) {
1925
+ this._showWarning = value;
1926
+ this.notify();
1927
+ }
1928
+ setIsTracking(value) {
1929
+ this._isTracking = value;
1930
+ this.notify();
1931
+ }
1932
+ triggerWarning(timeRemaining) {
1933
+ this._showInactivityWarning = true;
1934
+ this._inactivityTimeRemaining = Math.ceil(timeRemaining / 1e3);
1935
+ this._showWarning = true;
1936
+ this.notify();
1937
+ }
1938
+ triggerIdle() {
1939
+ this._isIdle = true;
1940
+ this.handleIdleLogout();
1941
+ this.notify();
1942
+ }
1943
+ // Update dependencies
1944
+ updateDependencies(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout) {
1945
+ this.supabaseClient = supabaseClient;
1946
+ this.user = user;
1947
+ this.session = session;
1948
+ if (idleTimeoutMs !== void 0) this.idleTimeoutMs = idleTimeoutMs;
1949
+ if (warnBeforeMs !== void 0) this.warnBeforeMs = warnBeforeMs;
1950
+ if (onIdleLogout !== void 0) this.onIdleLogout = onIdleLogout;
1951
+ this.notify();
1952
+ }
1953
+ // Inactivity methods
1954
+ resetActivity() {
1955
+ if (this.inactivityTracker) {
1956
+ this.inactivityTracker.resetActivity();
1957
+ }
1958
+ const prevIsIdle = this._isIdle;
1959
+ const prevShowWarning = this._showWarning;
1960
+ const prevShowInactivityWarning = this._showInactivityWarning;
1961
+ const prevInactivityTimeRemaining = this._inactivityTimeRemaining;
1962
+ const prevTimeRemaining = this._timeRemaining;
1963
+ this._isIdle = false;
1964
+ this._showWarning = false;
1965
+ this._showInactivityWarning = false;
1966
+ this._inactivityTimeRemaining = 0;
1967
+ this._timeRemaining = this.idleTimeoutMs;
1968
+ if (prevIsIdle !== this._isIdle || prevShowWarning !== this._showWarning || prevShowInactivityWarning !== this._showInactivityWarning || prevInactivityTimeRemaining !== this._inactivityTimeRemaining || prevTimeRemaining !== this._timeRemaining) {
1969
+ this.notify();
1970
+ }
1971
+ }
1972
+ startTracking() {
1973
+ if (this.inactivityTracker) {
1974
+ this.inactivityTracker.startTracking();
1975
+ }
1976
+ this._isTracking = true;
1977
+ this.notify();
1978
+ }
1979
+ stopTracking() {
1980
+ if (this.inactivityTracker) {
1981
+ this.inactivityTracker.stopTracking();
1982
+ }
1983
+ this._isTracking = false;
1984
+ this.notify();
1985
+ }
1986
+ async handleIdleLogout() {
1987
+ this._showInactivityWarning = false;
1988
+ this._inactivityTimeRemaining = 0;
1989
+ this.stopTracking();
1990
+ try {
1991
+ if (this.supabaseClient) {
1992
+ await this.supabaseClient.auth.signOut();
1993
+ }
1994
+ } catch (error) {
1995
+ logger.error("InactivityService", "Error during idle logout:", error);
1996
+ }
1997
+ try {
1998
+ sessionStorage.clear();
1999
+ } catch (storageError) {
2000
+ logger.warn("InactivityService", "Failed to clear sessionStorage", { error: storageError });
2001
+ }
2002
+ this.onIdleLogout?.("inactivity");
2003
+ this.notify();
2004
+ }
2005
+ handleStaySignedIn() {
2006
+ this._showInactivityWarning = false;
2007
+ this._inactivityTimeRemaining = 0;
2008
+ this.resetActivity();
2009
+ this.notify();
2010
+ }
2011
+ async handleSignOutNow() {
2012
+ this._showInactivityWarning = false;
2013
+ this._inactivityTimeRemaining = 0;
2014
+ this.stopTracking();
2015
+ try {
2016
+ if (this.supabaseClient) {
2017
+ await this.supabaseClient.auth.signOut();
2018
+ }
2019
+ } catch (error) {
2020
+ logger.error("InactivityService", "Error during manual sign out:", error);
2021
+ }
2022
+ try {
2023
+ sessionStorage.clear();
2024
+ } catch (storageError) {
2025
+ logger.warn("InactivityService", "Failed to clear sessionStorage", { error: storageError });
2026
+ }
2027
+ this.onIdleLogout?.("inactivity");
2028
+ this.notify();
2029
+ }
2030
+ // Lifecycle methods
2031
+ async initialize() {
2032
+ await super.initialize();
2033
+ await this.setupInactivityTracker();
2034
+ }
2035
+ cleanup() {
2036
+ if (this.cleanupHandlers) {
2037
+ this.cleanupHandlers();
2038
+ this.cleanupHandlers = null;
2039
+ }
2040
+ if (this.inactivityTracker) {
2041
+ this.inactivityTracker = null;
2042
+ }
2043
+ this._isTracking = false;
2044
+ this._isIdle = false;
2045
+ this._showWarning = false;
2046
+ this._showInactivityWarning = false;
2047
+ this._timeRemaining = 0;
2048
+ this._inactivityTimeRemaining = 0;
2049
+ super.cleanup();
2050
+ }
2051
+ async doInitialize() {
2052
+ if (typeof window !== "undefined") {
2053
+ const isProduction = import.meta.env.MODE === "production";
2054
+ if (isProduction) {
2055
+ logger.warn("InactivityService", "Inactivity feature enabled in production");
2056
+ }
2057
+ }
2058
+ }
2059
+ doCleanup() {
2060
+ }
2061
+ async setupInactivityTracker() {
2062
+ if (typeof window === "undefined") return;
2063
+ this.isInactivityEnabled = !!(this.user && this.session);
2064
+ if (!this.isInactivityEnabled) {
2065
+ return;
2066
+ }
2067
+ this.setupEventHandlers();
2068
+ }
2069
+ runUpdateState(ctx, forceNotify = false) {
2070
+ const now = Date.now();
2071
+ const timeSinceActivity = now - ctx.lastActivity;
2072
+ const timeUntilIdle = this.idleTimeoutMs - timeSinceActivity;
2073
+ const newIsIdle = timeSinceActivity >= this.idleTimeoutMs;
2074
+ const newShowWarning = timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs && !newIsIdle;
2075
+ const newShowInactivityWarning = newShowWarning;
2076
+ const newInactivityTimeRemaining = newShowWarning ? Math.ceil(timeUntilIdle / 1e3) : 0;
2077
+ const newTimeRemaining = Math.max(0, timeUntilIdle);
2078
+ const stateChanged = ctx.prevIsIdle !== newIsIdle || ctx.prevShowWarning !== newShowWarning || ctx.prevShowInactivityWarning !== newShowInactivityWarning || newShowWarning && ctx.prevInactivityTimeRemaining !== newInactivityTimeRemaining || ctx.prevTimeRemaining !== newTimeRemaining;
2079
+ if (stateChanged || forceNotify) {
2080
+ this._isIdle = newIsIdle;
2081
+ this._showWarning = newShowWarning;
2082
+ this._showInactivityWarning = newShowInactivityWarning;
2083
+ this._inactivityTimeRemaining = newInactivityTimeRemaining;
2084
+ this._timeRemaining = newTimeRemaining;
2085
+ ctx.prevIsIdle = newIsIdle;
2086
+ ctx.prevShowWarning = newShowWarning;
2087
+ ctx.prevShowInactivityWarning = newShowInactivityWarning;
2088
+ ctx.prevInactivityTimeRemaining = newInactivityTimeRemaining;
2089
+ ctx.prevTimeRemaining = newTimeRemaining;
2090
+ if (stateChanged) {
2091
+ this.notify();
2092
+ }
2093
+ if (newIsIdle) {
2094
+ this.handleIdleLogout();
2095
+ }
2096
+ }
2097
+ }
2098
+ runScheduleNextCheck(ctx) {
2099
+ if (ctx.warningTimer) {
2100
+ clearTimeout(ctx.warningTimer);
2101
+ ctx.warningTimer = null;
2102
+ }
2103
+ if (ctx.logoutTimer) {
2104
+ clearTimeout(ctx.logoutTimer);
2105
+ ctx.logoutTimer = null;
2106
+ }
2107
+ if (ctx.countdownInterval) {
2108
+ clearInterval(ctx.countdownInterval);
2109
+ ctx.countdownInterval = null;
2110
+ }
2111
+ const getTimeUntilWarning = () => Math.max(0, this.idleTimeoutMs - this.warnBeforeMs - (Date.now() - ctx.lastActivity));
2112
+ const getTimeUntilLogout = () => Math.max(0, this.idleTimeoutMs - (Date.now() - ctx.lastActivity));
2113
+ const timeUntilWarning = getTimeUntilWarning();
2114
+ const timeUntilLogout = getTimeUntilLogout();
2115
+ const timeSinceActivity = Date.now() - ctx.lastActivity;
2116
+ if (timeSinceActivity >= this.idleTimeoutMs) {
2117
+ return;
2118
+ }
2119
+ if (timeSinceActivity >= this.idleTimeoutMs - this.warnBeforeMs) {
2120
+ this.runUpdateState(ctx);
2121
+ ctx.countdownInterval = setInterval(() => {
2122
+ this.runUpdateState(ctx);
2123
+ if (Date.now() - ctx.lastActivity >= this.idleTimeoutMs) {
2124
+ if (ctx.countdownInterval) {
2125
+ clearInterval(ctx.countdownInterval);
2126
+ ctx.countdownInterval = null;
2127
+ }
2128
+ this.handleIdleLogout();
2129
+ }
2130
+ }, 1e3);
2131
+ ctx.logoutTimer = setTimeout(() => {
2132
+ if (ctx.countdownInterval) {
2133
+ clearInterval(ctx.countdownInterval);
2134
+ ctx.countdownInterval = null;
2135
+ }
2136
+ this.handleIdleLogout();
2137
+ }, timeUntilLogout);
2138
+ } else {
2139
+ const timeUntilWarningMs = timeUntilWarning;
2140
+ const adaptiveInterval = timeUntilWarningMs > 5 * 60 * 1e3 ? 60 * 1e3 : timeUntilWarningMs > 60 * 1e3 ? 10 * 1e3 : 1e3;
2141
+ ctx.warningTimer = setTimeout(() => {
2142
+ this.runUpdateState(ctx);
2143
+ this.runScheduleNextCheck(ctx);
2144
+ }, Math.min(adaptiveInterval, timeUntilWarningMs));
2145
+ }
2146
+ }
2147
+ runResetTimers(ctx) {
2148
+ ctx.lastActivity = Date.now();
2149
+ if (ctx.warningTimer) {
2150
+ clearTimeout(ctx.warningTimer);
2151
+ ctx.warningTimer = null;
2152
+ }
2153
+ if (ctx.logoutTimer) {
2154
+ clearTimeout(ctx.logoutTimer);
2155
+ ctx.logoutTimer = null;
2156
+ }
2157
+ if (ctx.countdownInterval) {
2158
+ clearInterval(ctx.countdownInterval);
2159
+ ctx.countdownInterval = null;
2160
+ }
2161
+ const hadWarning = this._showWarning || this._showInactivityWarning;
2162
+ this._showInactivityWarning = false;
2163
+ this._inactivityTimeRemaining = 0;
2164
+ this._isIdle = false;
2165
+ this._showWarning = false;
2166
+ this._timeRemaining = this.idleTimeoutMs;
2167
+ ctx.prevIsIdle = false;
2168
+ ctx.prevShowWarning = false;
2169
+ ctx.prevShowInactivityWarning = false;
2170
+ ctx.prevInactivityTimeRemaining = 0;
2171
+ ctx.prevTimeRemaining = this.idleTimeoutMs;
2172
+ if (hadWarning) {
2173
+ this.notify();
2174
+ }
2175
+ this.runScheduleNextCheck(ctx);
2176
+ }
2177
+ setupEventHandlers() {
2178
+ if (typeof window === "undefined") return;
2179
+ const ctx = {
2180
+ warningTimer: null,
2181
+ logoutTimer: null,
2182
+ countdownInterval: null,
2183
+ activityThrottleTimer: null,
2184
+ lastActivity: Date.now(),
2185
+ prevIsIdle: false,
2186
+ prevShowWarning: false,
2187
+ prevShowInactivityWarning: false,
2188
+ prevInactivityTimeRemaining: 0,
2189
+ prevTimeRemaining: this.idleTimeoutMs
2190
+ };
2191
+ const activityEvents = ["mousedown", "mousemove", "keypress", "scroll", "touchstart", "click"];
2192
+ const handleActivity = () => {
2193
+ if (ctx.activityThrottleTimer) return;
2194
+ ctx.activityThrottleTimer = setTimeout(() => {
2195
+ ctx.activityThrottleTimer = null;
2196
+ this.runResetTimers(ctx);
2197
+ }, 1e3);
2198
+ };
2199
+ activityEvents.forEach((event) => {
2200
+ document.addEventListener(event, handleActivity, true);
2201
+ });
2202
+ this.runUpdateState(ctx, true);
2203
+ this.runScheduleNextCheck(ctx);
2204
+ this.cleanupHandlers = () => {
2205
+ if (ctx.warningTimer) {
2206
+ clearTimeout(ctx.warningTimer);
2207
+ ctx.warningTimer = null;
2208
+ }
2209
+ if (ctx.logoutTimer) {
2210
+ clearTimeout(ctx.logoutTimer);
2211
+ ctx.logoutTimer = null;
2212
+ }
2213
+ if (ctx.countdownInterval) {
2214
+ clearInterval(ctx.countdownInterval);
2215
+ ctx.countdownInterval = null;
2216
+ }
2217
+ if (ctx.activityThrottleTimer) {
2218
+ clearTimeout(ctx.activityThrottleTimer);
2219
+ ctx.activityThrottleTimer = null;
2220
+ }
2221
+ activityEvents.forEach((event) => {
2222
+ document.removeEventListener(event, handleActivity, true);
2223
+ });
2224
+ this._isTracking = false;
2225
+ this._isIdle = false;
2226
+ this._showWarning = false;
2227
+ this._timeRemaining = 0;
2228
+ this._showInactivityWarning = false;
2229
+ this._inactivityTimeRemaining = 0;
2230
+ };
2231
+ this._isTracking = true;
2232
+ }
2233
+ };
2234
+ function InactivityServiceProvider({
2235
+ children,
2236
+ supabaseClient,
2237
+ user,
2238
+ session,
2239
+ idleTimeoutMs,
2240
+ // REQUIRED: No default - must be explicitly provided
2241
+ warnBeforeMs,
2242
+ // REQUIRED: No default - must be explicitly provided
2243
+ onIdleLogout
2244
+ }) {
2245
+ const inactivityServiceRef = useRef(null);
2246
+ if (!inactivityServiceRef.current) {
2247
+ inactivityServiceRef.current = new InactivityService(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout);
2248
+ }
2249
+ const inactivityService = inactivityServiceRef.current;
2250
+ useEffect(() => {
2251
+ inactivityService.updateDependencies(supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout);
2252
+ let isMounted = true;
2253
+ inactivityService.initialize().catch((error) => {
2254
+ if (isMounted) {
2255
+ logger.error("InactivityServiceProvider", "Failed to initialize inactivity service:", error);
2256
+ }
2257
+ });
2258
+ return () => {
2259
+ isMounted = false;
2260
+ };
2261
+ }, [inactivityService, supabaseClient, user, session, idleTimeoutMs, warnBeforeMs, onIdleLogout]);
2262
+ useEffect(() => {
2263
+ return () => {
2264
+ inactivityService.cleanup();
2265
+ };
2266
+ }, [inactivityService]);
2267
+ const contextValue = useMemo(() => ({
2268
+ inactivityService
2269
+ }), [inactivityService]);
2270
+ return /* @__PURE__ */ jsx(InactivityServiceContext.Provider, { value: contextValue, children });
2271
+ }
2272
+ function useAuthService() {
2273
+ const context = useContext(AuthServiceContext);
2274
+ if (!context) {
2275
+ throw new Error("useAuthService must be used within AuthServiceProvider");
2276
+ }
2277
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
2278
+ const timeoutRef = useRef(null);
2279
+ useEffect(() => {
2280
+ const debouncedUpdate = () => {
2281
+ if (timeoutRef.current) {
2282
+ clearTimeout(timeoutRef.current);
2283
+ }
2284
+ timeoutRef.current = setTimeout(() => {
2285
+ forceUpdate();
2286
+ timeoutRef.current = null;
2287
+ }, 50);
2288
+ };
2289
+ const unsubscribe = context.authService.subscribe(debouncedUpdate);
2290
+ return () => {
2291
+ unsubscribe();
2292
+ if (timeoutRef.current) {
2293
+ clearTimeout(timeoutRef.current);
2294
+ }
2295
+ };
2296
+ }, [context.authService]);
2297
+ return context.authService;
2298
+ }
2299
+ function useOrganisationService() {
2300
+ const context = useContext(OrganisationServiceContext);
2301
+ if (!context) {
2302
+ throw new Error("useOrganisationService must be used within OrganisationServiceProvider");
2303
+ }
2304
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
2305
+ const timeoutRef = useRef(null);
2306
+ useEffect(() => {
2307
+ const debouncedUpdate = () => {
2308
+ if (timeoutRef.current) {
2309
+ clearTimeout(timeoutRef.current);
2310
+ }
2311
+ timeoutRef.current = setTimeout(() => {
2312
+ forceUpdate();
2313
+ timeoutRef.current = null;
2314
+ }, 50);
2315
+ };
2316
+ const unsubscribe = context.organisationService.subscribe(debouncedUpdate);
2317
+ return () => {
2318
+ unsubscribe();
2319
+ if (timeoutRef.current) {
2320
+ clearTimeout(timeoutRef.current);
2321
+ }
2322
+ };
2323
+ }, [context.organisationService]);
2324
+ return context.organisationService;
2325
+ }
2326
+
2327
+ // src/hooks/useOrganisations.ts
2328
+ function useOrganisations() {
2329
+ const organisationService = useOrganisationService();
2330
+ const selectedOrg = organisationService.getSelectedOrganisation();
2331
+ return {
2332
+ selectedOrganisation: selectedOrg,
2333
+ organisations: organisationService.getOrganisations(),
2334
+ userMemberships: organisationService.getUserMemberships(),
2335
+ isLoading: organisationService.isLoading(),
2336
+ error: organisationService.getError(),
2337
+ hasValidOrganisationContext: organisationService.hasValidOrganisationContext(),
2338
+ isContextReady: organisationService.isContextReady(),
2339
+ setSelectedOrganisation: (org) => organisationService.setSelectedOrganisation(org),
2340
+ switchOrganisation: (orgId) => organisationService.switchOrganisation(orgId),
2341
+ getUserRole: (orgId) => organisationService.getUserRole(orgId),
2342
+ validateOrganisationAccess: (orgId) => organisationService.validateOrganisationAccess(orgId),
2343
+ refreshOrganisations: () => organisationService.refreshOrganisations(),
2344
+ ensureOrganisationContext: () => organisationService.ensureOrganisationContext(),
2345
+ isOrganisationSecure: () => organisationService.isOrganisationSecure(),
2346
+ getPrimaryOrganisation: () => organisationService.getPrimaryOrganisation()
2347
+ };
2348
+ }
2349
+ function useEventService() {
2350
+ const context = useContext(EventServiceContext);
2351
+ if (!context) {
2352
+ throw new Error("useEventService must be used within EventServiceProvider");
2353
+ }
2354
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
2355
+ const timeoutRef = useRef(null);
2356
+ useEffect(() => {
2357
+ const debouncedUpdate = () => {
2358
+ if (timeoutRef.current) {
2359
+ clearTimeout(timeoutRef.current);
2360
+ }
2361
+ timeoutRef.current = setTimeout(() => {
2362
+ forceUpdate();
2363
+ timeoutRef.current = null;
2364
+ }, 50);
2365
+ };
2366
+ const unsubscribe = context.eventService.subscribe(debouncedUpdate);
2367
+ return () => {
2368
+ unsubscribe();
2369
+ if (timeoutRef.current) {
2370
+ clearTimeout(timeoutRef.current);
2371
+ }
2372
+ };
2373
+ }, [context.eventService]);
2374
+ return context.eventService;
2375
+ }
2376
+ function useInactivityService() {
2377
+ const context = useContext(InactivityServiceContext);
2378
+ if (!context) {
2379
+ throw new Error("useInactivityService must be used within InactivityServiceProvider");
2380
+ }
2381
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
2382
+ const timeoutRef = useRef(null);
2383
+ useEffect(() => {
2384
+ const debouncedUpdate = () => {
2385
+ if (timeoutRef.current) {
2386
+ clearTimeout(timeoutRef.current);
2387
+ }
2388
+ timeoutRef.current = setTimeout(() => {
2389
+ forceUpdate();
2390
+ timeoutRef.current = null;
2391
+ }, 50);
2392
+ };
2393
+ const unsubscribe = context.inactivityService.subscribe(debouncedUpdate);
2394
+ return () => {
2395
+ unsubscribe();
2396
+ if (timeoutRef.current) {
2397
+ clearTimeout(timeoutRef.current);
2398
+ }
2399
+ };
2400
+ }, [context.inactivityService]);
2401
+ return context.inactivityService;
2402
+ }
2403
+ var log = createLogger("useSessionRestoration");
2404
+ var SESSION_RESTORATION_TIMEOUT_MS = 1e4;
2405
+ function useSessionRestoration() {
2406
+ const context = useContext(AuthServiceContext);
2407
+ if (!context) {
2408
+ throw new Error("useSessionRestoration must be used within AuthServiceProvider");
2409
+ }
2410
+ const { sessionRestoration } = context;
2411
+ const [hasTimedOut, setHasTimedOut] = useState(false);
2412
+ useEffect(() => {
2413
+ let timeoutHandle = null;
2414
+ if (sessionRestoration.isRestoring && !sessionRestoration.restorationComplete && !sessionRestoration.restorationError) {
2415
+ setHasTimedOut(false);
2416
+ timeoutHandle = setTimeout(() => {
2417
+ log.warn("Session restoration timed out");
2418
+ setHasTimedOut(true);
2419
+ }, SESSION_RESTORATION_TIMEOUT_MS);
2420
+ } else {
2421
+ setHasTimedOut(false);
2422
+ }
2423
+ return () => {
2424
+ if (timeoutHandle) {
2425
+ clearTimeout(timeoutHandle);
2426
+ }
2427
+ };
2428
+ }, [
2429
+ sessionRestoration.isRestoring,
2430
+ sessionRestoration.restorationComplete,
2431
+ sessionRestoration.restorationError
2432
+ ]);
2433
+ return useMemo(() => ({
2434
+ ...sessionRestoration,
2435
+ hasTimedOut,
2436
+ timeoutMs: SESSION_RESTORATION_TIMEOUT_MS
2437
+ }), [sessionRestoration, hasTimedOut]);
2438
+ }
2439
+ var UnifiedAuthContext = createContext(void 0);
2440
+ function useUnifiedAuth() {
2441
+ const context = useContext(UnifiedAuthContext);
2442
+ if (!context) {
2443
+ logger.error("useUnifiedAuth", "useUnifiedAuth must be used within a UnifiedAuthProvider");
2444
+ throw new Error("useUnifiedAuth must be used within a UnifiedAuthProvider");
2445
+ }
2446
+ return context;
2447
+ }
2448
+ function useAppIdResolution(supabase, appName, isAuth, currentUserId) {
2449
+ const [appId, setAppId] = useState(void 0);
2450
+ const isResolvingAppIdRef = useRef(false);
2451
+ const resolvedAppIdRef = useRef(void 0);
2452
+ const resolvedUserIdRef = useRef(void 0);
2453
+ useEffect(() => {
2454
+ if (!isAuth) {
2455
+ resolvedAppIdRef.current = void 0;
2456
+ resolvedUserIdRef.current = void 0;
2457
+ setAppId(void 0);
2458
+ return;
2459
+ }
2460
+ if (currentUserId && resolvedUserIdRef.current && resolvedUserIdRef.current !== currentUserId) {
2461
+ resolvedAppIdRef.current = void 0;
2462
+ resolvedUserIdRef.current = void 0;
2463
+ setAppId(void 0);
2464
+ }
2465
+ const shouldResolve = isAuth && currentUserId && supabase && appName && resolvedUserIdRef.current !== currentUserId && !isResolvingAppIdRef.current;
2466
+ if (!shouldResolve) return;
2467
+ isResolvingAppIdRef.current = true;
2468
+ resolvedUserIdRef.current = currentUserId;
2469
+ const userId = currentUserId;
2470
+ const appNameValue = appName;
2471
+ import('./api-6OQXYT67.js').then(async ({ resolveAppContext, setupRBAC: setupRBAC2 }) => {
2472
+ try {
2473
+ setupRBAC2(supabase);
2474
+ const result = await resolveAppContext({ userId, appName: appNameValue });
2475
+ if (result.ok && result.data?.appId) {
2476
+ const appIdValue = result.data.appId;
2477
+ resolvedAppIdRef.current = appIdValue;
2478
+ setAppId(appIdValue);
2479
+ } else {
2480
+ resolvedUserIdRef.current = void 0;
2481
+ }
2482
+ } catch (error) {
2483
+ logger.error("UnifiedAuthProvider", "Failed to resolve appId on login", {
2484
+ error: error instanceof Error ? error.message : String(error),
2485
+ appName: appNameValue,
2486
+ userId
2487
+ });
2488
+ resolvedUserIdRef.current = void 0;
2489
+ } finally {
2490
+ isResolvingAppIdRef.current = false;
2491
+ }
2492
+ }).catch((importError) => {
2493
+ logger.error("UnifiedAuthProvider", "Failed to import RBAC API", importError);
2494
+ isResolvingAppIdRef.current = false;
2495
+ resolvedUserIdRef.current = void 0;
2496
+ });
2497
+ }, [isAuth, currentUserId, supabase, appName]);
2498
+ return appId;
2499
+ }
2500
+ function useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService) {
2501
+ const [, forceUpdate] = useReducer((x) => x + 1, 0);
2502
+ const forceUpdateTimeoutRef = useRef(null);
2503
+ const debouncedForceUpdate = useCallback(() => {
2504
+ if (forceUpdateTimeoutRef.current) clearTimeout(forceUpdateTimeoutRef.current);
2505
+ forceUpdateTimeoutRef.current = setTimeout(() => {
2506
+ forceUpdate();
2507
+ forceUpdateTimeoutRef.current = null;
2508
+ }, 100);
2509
+ }, [forceUpdate]);
2510
+ const authServiceRef = useRef(authService);
2511
+ const organisationServiceRef = useRef(organisationService);
2512
+ const eventServiceRef = useRef(eventService);
2513
+ const inactivityServiceRef = useRef(inactivityService);
2514
+ useEffect(() => {
2515
+ authServiceRef.current = authService;
2516
+ organisationServiceRef.current = organisationService;
2517
+ eventServiceRef.current = eventService;
2518
+ inactivityServiceRef.current = inactivityService;
2519
+ }, [authService, organisationService, eventService, inactivityService]);
2520
+ useEffect(() => {
2521
+ const unsubAuth = authServiceRef.current.subscribe(debouncedForceUpdate);
2522
+ const unsubOrg = organisationServiceRef.current.subscribe(debouncedForceUpdate);
2523
+ const unsubEvent = eventServiceRef.current.subscribe(debouncedForceUpdate);
2524
+ const unsubInactivity = inactivityServiceRef.current.subscribe(debouncedForceUpdate);
2525
+ return () => {
2526
+ unsubAuth();
2527
+ unsubOrg();
2528
+ unsubEvent();
2529
+ unsubInactivity();
2530
+ if (forceUpdateTimeoutRef.current) clearTimeout(forceUpdateTimeoutRef.current);
2531
+ };
2532
+ }, [debouncedForceUpdate]);
2533
+ }
2534
+ function useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase) {
2535
+ return useMemo(
2536
+ () => {
2537
+ const selectedOrganisationId = state.selectedOrganisation?.id ?? state.selectedEvent?.organisation_id ?? null;
2538
+ return {
2539
+ user: state.currentUser,
2540
+ session: state.currentSession,
2541
+ isAuthenticated: state.isAuth,
2542
+ authLoading: state.authLoading,
2543
+ authError: state.authError,
2544
+ supabase,
2545
+ signIn: callbacks.signIn,
2546
+ signUp: callbacks.signUp,
2547
+ signOut: callbacks.signOut,
2548
+ resetPassword: callbacks.resetPassword,
2549
+ updatePassword: callbacks.updatePassword,
2550
+ refreshSession: callbacks.refreshSession,
2551
+ selectedOrganisation: state.selectedOrganisation,
2552
+ selectedOrganisationId,
2553
+ organisations: state.organisations,
2554
+ userMemberships: state.userMemberships,
2555
+ organisationLoading: state.orgLoading,
2556
+ organisationError: state.organisationError,
2557
+ hasValidOrganisationContext: state.hasValidOrganisationContext,
2558
+ isContextReady: state.isContextReady,
2559
+ switchOrganisation: callbacks.switchOrganisation,
2560
+ getUserRole: callbacks.getUserRole,
2561
+ validateOrganisationAccess: callbacks.validateOrganisationAccess,
2562
+ refreshOrganisations: callbacks.refreshOrganisations,
2563
+ ensureOrganisationContext: callbacks.ensureOrganisationContext,
2564
+ isOrganisationSecure: callbacks.isOrganisationSecure,
2565
+ getPrimaryOrganisation: callbacks.getPrimaryOrganisation,
2566
+ events: state.events,
2567
+ selectedEvent: state.selectedEvent,
2568
+ selectedEventId: state.selectedEvent?.event_id ?? null,
2569
+ eventLoading: state.eventLoading,
2570
+ eventError: state.eventError,
2571
+ setSelectedEvent: callbacks.setSelectedEvent,
2572
+ refreshEvents: callbacks.refreshEvents,
2573
+ showInactivityWarning: state.inactivityState.showInactivityWarning,
2574
+ inactivityTimeRemaining: state.inactivityState.inactivityTimeRemaining,
2575
+ isIdle: state.inactivityState.isIdle,
2576
+ timeRemaining: state.inactivityState.timeRemaining,
2577
+ showWarning: state.inactivityState.showWarning,
2578
+ isTracking: state.inactivityState.isTracking,
2579
+ resetActivity: callbacks.resetActivity,
2580
+ startTracking: callbacks.startTracking,
2581
+ stopTracking: callbacks.stopTracking,
2582
+ handleIdleLogout: callbacks.handleIdleLogout,
2583
+ handleStaySignedIn: callbacks.handleStaySignedIn,
2584
+ handleSignOutNow: callbacks.handleSignOutNow,
2585
+ appName,
2586
+ appId,
2587
+ isLoading: state.totalLoading,
2588
+ hasErrors: state.hasErrors,
2589
+ sessionRestoration: state.sessionRestoration,
2590
+ sessionRestorationTimedOut: state.sessionRestorationTimedOut,
2591
+ sessionRestorationTimeoutMs: state.sessionRestorationTimeoutMs
2592
+ };
2593
+ },
2594
+ [state, callbacks, appId, appName, supabase]
2595
+ );
2596
+ }
2597
+ function useUnifiedAuthStateAndCallbacks(authService, organisationService, eventService, inactivityService, sessionRestoration, sessionRestorationTimedOut, sessionRestorationTimeoutMs, appName, userOverride, sessionOverride) {
2598
+ const currentUser = userOverride !== void 0 ? userOverride : authService.getUser();
2599
+ const currentSession = sessionOverride !== void 0 ? sessionOverride : authService.getSession();
2600
+ const isAuth = !!(currentUser && currentSession);
2601
+ const authLoading = authService.isLoading();
2602
+ const orgLoading = organisationService.isLoading();
2603
+ const eventLoading = eventService.isLoading();
2604
+ const restorationLoading = sessionRestoration.isRestoring && !sessionRestorationTimedOut && !sessionRestoration.restorationError;
2605
+ const shouldIncludeOrgLoading = appName !== "ADMIN" && appName !== "PORTAL";
2606
+ const totalLoading = restorationLoading || authLoading || (shouldIncludeOrgLoading ? orgLoading : false) || eventLoading;
2607
+ const authError = authService.getError();
2608
+ const selectedOrganisation = organisationService.getSelectedOrganisation();
2609
+ const organisationError = organisationService.getError();
2610
+ const hasValidOrganisationContext = organisationService.hasValidOrganisationContext();
2611
+ const isContextReady = organisationService.isContextReady();
2612
+ const rawEvents = eventService.getEvents();
2613
+ const rawOrganisations = organisationService.getOrganisations();
2614
+ const rawUserMemberships = organisationService.getUserMemberships();
2615
+ const events = useMemo(() => rawEvents, [rawEvents]);
2616
+ const organisations = useMemo(() => rawOrganisations, [rawOrganisations]);
2617
+ const userMemberships = useMemo(() => rawUserMemberships, [rawUserMemberships]);
2618
+ const selectedEvent = eventService.getSelectedEvent();
2619
+ const eventError = eventService.getError();
2620
+ const showInactivityWarning = inactivityService.getShowInactivityWarning();
2621
+ const inactivityTimeRemaining = inactivityService.getInactivityTimeRemaining();
2622
+ const isIdle = inactivityService.isIdle();
2623
+ const timeRemaining = inactivityService.getTimeRemaining();
2624
+ const showWarning = inactivityService.isWarningShown();
2625
+ const isTracking = inactivityService.isTracking();
2626
+ const inactivityState = useMemo(() => ({
2627
+ showInactivityWarning,
2628
+ inactivityTimeRemaining,
2629
+ isIdle,
2630
+ timeRemaining,
2631
+ showWarning,
2632
+ isTracking
2633
+ }), [showInactivityWarning, inactivityTimeRemaining, isIdle, timeRemaining, showWarning, isTracking]);
2634
+ const hasErrors = !!(authError || organisationError || eventError || sessionRestoration.restorationError);
2635
+ const signIn = useCallback((email, password) => authService.signIn(email, password), [authService]);
2636
+ const signUp = useCallback((email, password) => authService.signUp(email, password), [authService]);
2637
+ const signOut = useCallback(() => authService.signOut(), [authService]);
2638
+ const resetPassword = useCallback((email) => authService.resetPassword(email), [authService]);
2639
+ const updatePassword = useCallback((password) => authService.updatePassword(password), [authService]);
2640
+ const refreshSession = useCallback(() => authService.refreshSession(), [authService]);
2641
+ const switchOrganisation = useCallback((orgId) => organisationService.switchOrganisation(orgId), [organisationService]);
2642
+ const getUserRole = useCallback((orgId) => organisationService.getUserRole(orgId), [organisationService]);
2643
+ const validateOrganisationAccess = useCallback((orgId) => organisationService.validateOrganisationAccess(orgId), [organisationService]);
2644
+ const refreshOrganisations = useCallback(() => organisationService.refreshOrganisations(), [organisationService]);
2645
+ const ensureOrganisationContext = useCallback(() => organisationService.ensureOrganisationContext(), [organisationService]);
2646
+ const isOrganisationSecure = useCallback(() => organisationService.isOrganisationSecure(), [organisationService]);
2647
+ const getPrimaryOrganisation = useCallback(() => organisationService.getPrimaryOrganisation(), [organisationService]);
2648
+ const setSelectedEvent = useCallback((event) => eventService.setSelectedEvent(event), [eventService]);
2649
+ const refreshEvents = useCallback(() => eventService.refreshEvents(), [eventService]);
2650
+ const resetActivity = useCallback(() => inactivityService.resetActivity(), [inactivityService]);
2651
+ const startTracking = useCallback(() => inactivityService.startTracking(), [inactivityService]);
2652
+ const stopTracking = useCallback(() => inactivityService.stopTracking(), [inactivityService]);
2653
+ const handleIdleLogout = useCallback(() => inactivityService.handleIdleLogout(), [inactivityService]);
2654
+ const handleStaySignedIn = useCallback(() => inactivityService.handleStaySignedIn(), [inactivityService]);
2655
+ const handleSignOutNow = useCallback(() => inactivityService.handleSignOutNow(), [inactivityService]);
2656
+ const state = useMemo(() => ({
2657
+ currentUser,
2658
+ currentSession,
2659
+ isAuth,
2660
+ authLoading,
2661
+ authError,
2662
+ selectedOrganisation,
2663
+ organisations,
2664
+ userMemberships,
2665
+ orgLoading,
2666
+ organisationError,
2667
+ hasValidOrganisationContext,
2668
+ isContextReady,
2669
+ events,
2670
+ selectedEvent,
2671
+ eventLoading,
2672
+ eventError,
2673
+ inactivityState,
2674
+ totalLoading,
2675
+ hasErrors,
2676
+ sessionRestoration,
2677
+ sessionRestorationTimedOut,
2678
+ sessionRestorationTimeoutMs
2679
+ }), [
2680
+ currentUser,
2681
+ currentSession,
2682
+ isAuth,
2683
+ authLoading,
2684
+ authError,
2685
+ selectedOrganisation,
2686
+ organisations,
2687
+ userMemberships,
2688
+ orgLoading,
2689
+ organisationError,
2690
+ hasValidOrganisationContext,
2691
+ isContextReady,
2692
+ events,
2693
+ selectedEvent,
2694
+ eventLoading,
2695
+ eventError,
2696
+ inactivityState,
2697
+ totalLoading,
2698
+ hasErrors,
2699
+ sessionRestoration,
2700
+ sessionRestorationTimedOut,
2701
+ sessionRestorationTimeoutMs
2702
+ ]);
2703
+ const callbacks = useMemo(() => ({
2704
+ signIn,
2705
+ signUp,
2706
+ signOut,
2707
+ resetPassword,
2708
+ updatePassword,
2709
+ refreshSession,
2710
+ switchOrganisation,
2711
+ getUserRole,
2712
+ validateOrganisationAccess,
2713
+ refreshOrganisations,
2714
+ ensureOrganisationContext,
2715
+ isOrganisationSecure,
2716
+ getPrimaryOrganisation,
2717
+ setSelectedEvent,
2718
+ refreshEvents,
2719
+ resetActivity,
2720
+ startTracking,
2721
+ stopTracking,
2722
+ handleIdleLogout,
2723
+ handleStaySignedIn,
2724
+ handleSignOutNow
2725
+ }), [
2726
+ signIn,
2727
+ signUp,
2728
+ signOut,
2729
+ resetPassword,
2730
+ updatePassword,
2731
+ refreshSession,
2732
+ switchOrganisation,
2733
+ getUserRole,
2734
+ validateOrganisationAccess,
2735
+ refreshOrganisations,
2736
+ ensureOrganisationContext,
2737
+ isOrganisationSecure,
2738
+ getPrimaryOrganisation,
2739
+ setSelectedEvent,
2740
+ refreshEvents,
2741
+ resetActivity,
2742
+ startTracking,
2743
+ stopTracking,
2744
+ handleIdleLogout,
2745
+ handleStaySignedIn,
2746
+ handleSignOutNow
2747
+ ]);
2748
+ return { state, callbacks };
2749
+ }
2750
+ function UnifiedAuthContextProvider({
2751
+ children,
2752
+ appName,
2753
+ supabaseClient: supabaseClientProp,
2754
+ user: userFromParent,
2755
+ session: sessionFromParent
2756
+ }) {
2757
+ const authService = useAuthService();
2758
+ const organisationService = useOrganisationService();
2759
+ const inactivityService = useInactivityService();
2760
+ const eventService = useEventService();
2761
+ const sessionRestorationState = useSessionRestoration();
2762
+ const sessionRestoration = useMemo(() => ({
2763
+ isRestoring: sessionRestorationState.isRestoring,
2764
+ restorationComplete: sessionRestorationState.restorationComplete,
2765
+ restorationError: sessionRestorationState.restorationError
2766
+ }), [sessionRestorationState.isRestoring, sessionRestorationState.restorationComplete, sessionRestorationState.restorationError]);
2767
+ const { hasTimedOut: sessionRestorationTimedOut, timeoutMs: sessionRestorationTimeoutMs } = sessionRestorationState;
2768
+ const currentUser = userFromParent !== void 0 ? userFromParent : authService.getUser();
2769
+ const currentSession = sessionFromParent !== void 0 ? sessionFromParent : authService.getSession();
2770
+ const isAuth = !!(currentUser && currentSession);
2771
+ const supabase = useMemo(() => supabaseClientProp, [supabaseClientProp]);
2772
+ const appId = useAppIdResolution(supabase, appName, isAuth, currentUser?.id);
2773
+ useUnifiedAuthSubscriptions(authService, organisationService, eventService, inactivityService);
2774
+ const { state, callbacks } = useUnifiedAuthStateAndCallbacks(
2775
+ authService,
2776
+ organisationService,
2777
+ eventService,
2778
+ inactivityService,
2779
+ sessionRestoration,
2780
+ sessionRestorationTimedOut,
2781
+ sessionRestorationTimeoutMs,
2782
+ appName,
2783
+ currentUser,
2784
+ currentSession
2785
+ );
2786
+ const contextValue = useUnifiedAuthContextValue(state, callbacks, appId, appName, supabase);
2787
+ useEffect(() => {
2788
+ if (appName) setPrintAppName(appName);
2789
+ }, [appName]);
2790
+ return /* @__PURE__ */ jsx(UnifiedAuthContext.Provider, { value: contextValue, children });
2791
+ }
2792
+ function EventServiceProviderWrapper({
2793
+ children,
2794
+ supabaseClient,
2795
+ user,
2796
+ session,
2797
+ appName
2798
+ }) {
2799
+ const { selectedOrganisation } = useOrganisations();
2800
+ const setSelectedEventId = useCallback(() => {
2801
+ }, []);
2802
+ useEffect(() => {
2803
+ }, [user?.id, session?.access_token, selectedOrganisation?.id]);
2804
+ return /* @__PURE__ */ jsx(
2805
+ EventServiceProvider,
2806
+ {
2807
+ supabaseClient,
2808
+ user,
2809
+ session,
2810
+ appName,
2811
+ selectedOrganisation,
2812
+ setSelectedEventId,
2813
+ children
2814
+ }
2815
+ );
2816
+ }
2817
+ function ServiceAwareProviders({
2818
+ children,
2819
+ supabaseClient,
2820
+ appName,
2821
+ persistState,
2822
+ enablePersistence,
2823
+ requireOrganisationContext,
2824
+ idleTimeoutMs,
2825
+ warnBeforeMs,
2826
+ onIdleLogout,
2827
+ renderInactivityWarning,
2828
+ dangerouslyDisableInactivity
2829
+ }) {
2830
+ const authService = useAuthService();
2831
+ const [userState, setUserState] = useState(() => authService.getUser());
2832
+ const [sessionState, setSessionState] = useState(() => authService.getSession());
2833
+ useEffect(() => {
2834
+ const unsubscribe = authService.subscribe(() => {
2835
+ const newUser = authService.getUser();
2836
+ const newSession = authService.getSession();
2837
+ flushSync(() => {
2838
+ setUserState(newUser);
2839
+ setSessionState(newSession);
2840
+ });
2841
+ });
2842
+ return unsubscribe;
2843
+ }, [authService]);
2844
+ const user = userState;
2845
+ const session = sessionState;
2846
+ return /* @__PURE__ */ jsx(
2847
+ OrganisationServiceProvider,
2848
+ {
2849
+ supabaseClient,
2850
+ user,
2851
+ session,
2852
+ children: /* @__PURE__ */ jsx(
2853
+ EventServiceProviderWrapper,
2854
+ {
2855
+ supabaseClient,
2856
+ user,
2857
+ session,
2858
+ appName,
2859
+ children: /* @__PURE__ */ jsx(
2860
+ InactivityServiceProvider,
2861
+ {
2862
+ supabaseClient,
2863
+ user,
2864
+ session,
2865
+ idleTimeoutMs,
2866
+ warnBeforeMs,
2867
+ onIdleLogout,
2868
+ children: /* @__PURE__ */ jsx(
2869
+ UnifiedAuthContextProvider,
2870
+ {
2871
+ appName,
2872
+ supabaseClient,
2873
+ user,
2874
+ session,
2875
+ persistState,
2876
+ enablePersistence,
2877
+ requireOrganisationContext,
2878
+ idleTimeoutMs,
2879
+ warnBeforeMs,
2880
+ onIdleLogout,
2881
+ renderInactivityWarning,
2882
+ dangerouslyDisableInactivity,
2883
+ children
2884
+ }
2885
+ )
2886
+ }
2887
+ )
2888
+ }
2889
+ )
2890
+ }
2891
+ );
2892
+ }
2893
+ function UnifiedAuthProvider({
2894
+ children,
2895
+ supabaseClient,
2896
+ appName,
2897
+ persistState = true,
2898
+ enablePersistence,
2899
+ requireOrganisationContext = true,
2900
+ idleTimeoutMs,
2901
+ // REQUIRED: No default - must be explicitly provided
2902
+ warnBeforeMs,
2903
+ // REQUIRED: No default - must be explicitly provided
2904
+ onIdleLogout,
2905
+ // REQUIRED: No default - must be explicitly provided
2906
+ renderInactivityWarning,
2907
+ dangerouslyDisableInactivity = false
2908
+ }) {
2909
+ const clientRef = useRef(supabaseClient);
2910
+ useEffect(() => {
2911
+ if (clientRef.current !== supabaseClient) {
2912
+ logger.warn("UnifiedAuthProvider", "Supabase client reference changed - this may indicate multiple client instances are being created", {
2913
+ previousClient: clientRef.current,
2914
+ newClient: supabaseClient,
2915
+ note: 'Ensure you create the Supabase client once and reuse it. Creating multiple clients can cause performance issues and the "Multiple GoTrueClient instances" warning.'
2916
+ });
2917
+ clientRef.current = supabaseClient;
2918
+ }
2919
+ }, [supabaseClient]);
2920
+ if (supabaseClient && !isRBACInitialized()) {
2921
+ try {
2922
+ setupRBAC(supabaseClient);
2923
+ logger.debug("UnifiedAuthProvider", "RBAC initialized synchronously");
2924
+ } catch (err2) {
2925
+ logger.error("UnifiedAuthProvider", "Failed to initialize RBAC", err2);
2926
+ }
2927
+ }
2928
+ return /* @__PURE__ */ jsx(AuthServiceProvider, { supabaseClient, appName, children: /* @__PURE__ */ jsx(
2929
+ ServiceAwareProviders,
2930
+ {
2931
+ supabaseClient,
2932
+ appName,
2933
+ persistState,
2934
+ enablePersistence,
2935
+ requireOrganisationContext,
2936
+ idleTimeoutMs,
2937
+ warnBeforeMs,
2938
+ onIdleLogout,
2939
+ renderInactivityWarning,
2940
+ dangerouslyDisableInactivity,
2941
+ children
2942
+ }
2943
+ ) });
2944
+ }
2945
+
2946
+ export { AuthServiceProvider, EventServiceContext, EventServiceProvider, InactivityServiceContext, InactivityServiceProvider, OrganisationServiceContext, OrganisationServiceProvider, UnifiedAuthContext, UnifiedAuthProvider, useAuthService, useEventService, useInactivityService, useOrganisationService, useOrganisations, useSessionRestoration, useUnifiedAuth };