@jmruthers/pace-core 0.5.180 → 0.5.182

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 (750) hide show
  1. package/CHANGELOG.md +1 -1
  2. package/README.md +16 -2
  3. package/dist/{AuthService-DYuQPJj6.d.ts → AuthService-B-cd2MA4.d.ts} +9 -11
  4. package/dist/{DataTable-CWAZZcXC.d.ts → DataTable-Bz8ffqyA.d.ts} +1 -1
  5. package/dist/{DataTable-4VSEJQ7D.js → DataTable-QAB34V6K.js} +14 -15
  6. package/dist/UnifiedAuthProvider-7F6T4B6K.js +13 -0
  7. package/dist/{UnifiedAuthProvider-DJxGTftH.d.ts → UnifiedAuthProvider-F86d7dSi.d.ts} +5 -6
  8. package/dist/{api-45XYYO2A.js → api-ROMBCNKU.js} +5 -5
  9. package/dist/{audit-64X3VJXB.js → audit-WRS3KJKI.js} +4 -4
  10. package/dist/auth-BZOJqrdd.d.ts +49 -0
  11. package/dist/{chunk-CX5M4ZAG.js → chunk-5DRSZLL2.js} +1 -1
  12. package/dist/chunk-5DRSZLL2.js.map +1 -0
  13. package/dist/{chunk-BESYRHQM.js → chunk-6C4YBBJM.js} +10 -7
  14. package/dist/chunk-6C4YBBJM.js.map +1 -0
  15. package/dist/{chunk-PLDDJCW6.js → chunk-7D4SUZUM.js} +2 -13
  16. package/dist/{chunk-6HLVGAZG.js → chunk-CSOFYHAG.js} +55 -162
  17. package/dist/chunk-CSOFYHAG.js.map +1 -0
  18. package/dist/{chunk-ANBQRTPX.js → chunk-E66EQZE6.js} +3 -5
  19. package/dist/{chunk-ANBQRTPX.js.map → chunk-E66EQZE6.js.map} +1 -1
  20. package/dist/{chunk-Q5QRDWKI.js → chunk-F2IMUDXZ.js} +4 -6
  21. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  22. package/dist/{chunk-SBVILCCA.js → chunk-FSFQFJCU.js} +28 -6
  23. package/dist/chunk-FSFQFJCU.js.map +1 -0
  24. package/dist/chunk-FUEYYMX5.js +2296 -0
  25. package/dist/chunk-FUEYYMX5.js.map +1 -0
  26. package/dist/{chunk-FFKNH6U5.js → chunk-HKIT6O7W.js} +3 -5
  27. package/dist/{chunk-FFKNH6U5.js.map → chunk-HKIT6O7W.js.map} +1 -1
  28. package/dist/chunk-KQCRWDSA.js +1 -0
  29. package/dist/{chunk-S5OFRT4M.js → chunk-KUEN3HFB.js} +6 -6
  30. package/dist/chunk-KUEN3HFB.js.map +1 -0
  31. package/dist/chunk-LMC26NLJ.js +84 -0
  32. package/dist/chunk-LMC26NLJ.js.map +1 -0
  33. package/dist/{chunk-BVYWGZVV.js → chunk-M7W4CP3M.js} +52 -19
  34. package/dist/chunk-M7W4CP3M.js.map +1 -0
  35. package/dist/{chunk-CPTUD43C.js → chunk-MI7HBHN3.js} +164 -243
  36. package/dist/chunk-MI7HBHN3.js.map +1 -0
  37. package/dist/{chunk-N5YCCUG5.js → chunk-PWAHJW4G.js} +180 -29
  38. package/dist/chunk-PWAHJW4G.js.map +1 -0
  39. package/dist/chunk-PWLANIRT.js +127 -0
  40. package/dist/{chunk-XDNLUEXI.js.map → chunk-PWLANIRT.js.map} +1 -1
  41. package/dist/chunk-QCDXODCA.js +75 -0
  42. package/dist/chunk-QCDXODCA.js.map +1 -0
  43. package/dist/{chunk-P6UUHOIF.js → chunk-QETLRQI6.js} +526 -887
  44. package/dist/chunk-QETLRQI6.js.map +1 -0
  45. package/dist/{chunk-GQA2LIAE.js → chunk-QUVSNGIP.js} +264 -262
  46. package/dist/chunk-QUVSNGIP.js.map +1 -0
  47. package/dist/chunk-QXHPKYJV.js +113 -0
  48. package/dist/chunk-QXHPKYJV.js.map +1 -0
  49. package/dist/{chunk-OWAG3GSU.js → chunk-R77UEZ4E.js} +11 -1
  50. package/dist/chunk-R77UEZ4E.js.map +1 -0
  51. package/dist/{chunk-ONI7Y733.js → chunk-RA3JUFMW.js} +314 -161
  52. package/dist/chunk-RA3JUFMW.js.map +1 -0
  53. package/dist/{chunk-ERISIBYU.js → chunk-SQGMNID3.js} +3 -8
  54. package/dist/chunk-SQGMNID3.js.map +1 -0
  55. package/dist/{chunk-XJ2HZOBU.js → chunk-UHNYIBXL.js} +1 -1
  56. package/dist/chunk-UHNYIBXL.js.map +1 -0
  57. package/{src/utils/secureStorage.ts → dist/chunk-VBXEHIUJ.js} +113 -88
  58. package/dist/{chunk-7QCC6MCP.js.map → chunk-VBXEHIUJ.js.map} +1 -1
  59. package/dist/{chunk-R53TUSFK.js → chunk-W22JP75J.js} +5 -13
  60. package/dist/{chunk-R53TUSFK.js.map → chunk-W22JP75J.js.map} +1 -1
  61. package/dist/components.d.ts +12 -93
  62. package/dist/components.js +23 -106
  63. package/dist/components.js.map +1 -1
  64. package/dist/core-CUElvH_C.d.ts +164 -0
  65. package/dist/database.generated-CBmg2950.d.ts +8284 -0
  66. package/dist/event-CW5YB_2p.d.ts +239 -0
  67. package/dist/{file-reference-C6Gkn77H.d.ts → file-reference-D06mEEWW.d.ts} +7 -5
  68. package/dist/functions-D_kgHktt.d.ts +208 -0
  69. package/dist/hooks.d.ts +54 -7
  70. package/dist/hooks.js +204 -17
  71. package/dist/hooks.js.map +1 -1
  72. package/dist/{EventLogo-B3V3otev.d.ts → index-Bl--n7-T.d.ts} +387 -397
  73. package/dist/index.d.ts +94 -261
  74. package/dist/index.js +314 -126
  75. package/dist/index.js.map +1 -1
  76. package/dist/providers.d.ts +7 -8
  77. package/dist/providers.js +6 -13
  78. package/dist/rbac/index.d.ts +171 -101
  79. package/dist/rbac/index.js +23 -17
  80. package/dist/styles/index.d.ts +1 -3
  81. package/dist/styles/index.js +2 -17
  82. package/dist/theming/runtime.js +3 -3
  83. package/dist/types-UU913iLA.d.ts +102 -0
  84. package/dist/{types-Dfz9dmVH.d.ts → types-_x1f4QBF.d.ts} +6 -6
  85. package/dist/types.d.ts +88 -227
  86. package/dist/types.js +64 -112
  87. package/dist/types.js.map +1 -1
  88. package/dist/{usePublicRouteParams-B7PabvuH.d.ts → usePublicRouteParams-JJczomYq.d.ts} +203 -6
  89. package/dist/utils.d.ts +299 -13
  90. package/dist/utils.js +481 -55
  91. package/dist/utils.js.map +1 -1
  92. package/dist/validation-643vUDZW.d.ts +177 -0
  93. package/docs/DOCUMENTATION_REVIEW_TRACKER.md +511 -0
  94. package/docs/README.md +9 -8
  95. package/docs/api/README.md +16 -2
  96. package/docs/api/classes/ColumnFactory.md +1 -1
  97. package/docs/api/classes/ErrorBoundary.md +1 -1
  98. package/docs/api/classes/InvalidScopeError.md +4 -4
  99. package/docs/api/classes/MissingUserContextError.md +4 -4
  100. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  101. package/docs/api/classes/PermissionDeniedError.md +4 -4
  102. package/docs/api/classes/RBACAuditManager.md +14 -14
  103. package/docs/api/classes/RBACCache.md +1 -1
  104. package/docs/api/classes/RBACEngine.md +2 -2
  105. package/docs/api/classes/RBACError.md +4 -4
  106. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  107. package/docs/api/classes/SecureSupabaseClient.md +29 -9
  108. package/docs/api/classes/StorageUtils.md +1 -1
  109. package/docs/api/enums/FileCategory.md +17 -17
  110. package/docs/api/enums/RBACErrorCode.md +228 -0
  111. package/docs/api/enums/RPCFunction.md +118 -0
  112. package/docs/api/interfaces/AggregateConfig.md +1 -1
  113. package/docs/api/interfaces/BadgeProps.md +1 -1
  114. package/docs/api/interfaces/ButtonProps.md +2 -2
  115. package/docs/api/interfaces/CalendarProps.md +1 -1
  116. package/docs/api/interfaces/CardProps.md +29 -3
  117. package/docs/api/interfaces/ColorPalette.md +1 -1
  118. package/docs/api/interfaces/ColorShade.md +1 -1
  119. package/docs/api/interfaces/DataAccessRecord.md +1 -1
  120. package/docs/api/interfaces/DataRecord.md +1 -1
  121. package/docs/api/interfaces/DataTableAction.md +2 -2
  122. package/docs/api/interfaces/DataTableColumn.md +6 -6
  123. package/docs/api/interfaces/DataTableProps.md +1 -1
  124. package/docs/api/interfaces/DataTableToolbarButton.md +2 -2
  125. package/docs/api/interfaces/EmptyStateConfig.md +1 -1
  126. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  127. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  128. package/docs/api/interfaces/ExportColumn.md +5 -5
  129. package/docs/api/interfaces/ExportOptions.md +4 -4
  130. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  131. package/docs/api/interfaces/FileMetadata.md +13 -13
  132. package/docs/api/interfaces/FileReference.md +12 -12
  133. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  134. package/docs/api/interfaces/FileUploadOptions.md +10 -10
  135. package/docs/api/interfaces/FileUploadProps.md +19 -19
  136. package/docs/api/interfaces/FooterProps.md +1 -1
  137. package/docs/api/interfaces/FormFieldProps.md +166 -0
  138. package/docs/api/interfaces/FormProps.md +113 -0
  139. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  140. package/docs/api/interfaces/InactivityWarningModalProps.md +8 -8
  141. package/docs/api/interfaces/InputProps.md +2 -2
  142. package/docs/api/interfaces/LabelProps.md +8 -8
  143. package/docs/api/interfaces/LoginFormProps.md +1 -1
  144. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  145. package/docs/api/interfaces/NavigationContextType.md +1 -1
  146. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  147. package/docs/api/interfaces/NavigationItem.md +17 -73
  148. package/docs/api/interfaces/NavigationMenuProps.md +38 -53
  149. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  150. package/docs/api/interfaces/Organisation.md +13 -13
  151. package/docs/api/interfaces/OrganisationContextType.md +21 -21
  152. package/docs/api/interfaces/OrganisationMembership.md +15 -15
  153. package/docs/api/interfaces/OrganisationProviderProps.md +59 -2
  154. package/docs/api/interfaces/OrganisationSecurityError.md +5 -5
  155. package/docs/api/interfaces/PaceAppLayoutProps.md +26 -39
  156. package/docs/api/interfaces/PaceLoginPageProps.md +1 -1
  157. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  158. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  159. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  160. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  161. package/docs/api/interfaces/PaletteData.md +1 -1
  162. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  163. package/docs/api/interfaces/ProgressProps.md +50 -0
  164. package/docs/api/interfaces/ProtectedRouteProps.md +1 -1
  165. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  166. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  167. package/docs/api/interfaces/PublicPageLayoutProps.md +15 -15
  168. package/docs/api/interfaces/RBACAccessValidateParams.md +52 -0
  169. package/docs/api/interfaces/RBACAccessValidateResult.md +41 -0
  170. package/docs/api/interfaces/RBACAuditLogParams.md +85 -0
  171. package/docs/api/interfaces/RBACAuditLogResult.md +52 -0
  172. package/docs/api/interfaces/RBACConfig.md +2 -2
  173. package/docs/api/interfaces/RBACContext.md +52 -0
  174. package/docs/api/interfaces/RBACLogger.md +1 -1
  175. package/docs/api/interfaces/RBACPageAccessCheckParams.md +74 -0
  176. package/docs/api/interfaces/RBACPermissionCheckParams.md +74 -0
  177. package/docs/api/interfaces/RBACPermissionCheckResult.md +52 -0
  178. package/docs/api/interfaces/RBACPermissionsGetParams.md +63 -0
  179. package/docs/api/interfaces/RBACPermissionsGetResult.md +63 -0
  180. package/docs/api/interfaces/RBACResult.md +58 -0
  181. package/docs/api/interfaces/RBACRoleGrantParams.md +63 -0
  182. package/docs/api/interfaces/RBACRoleGrantResult.md +52 -0
  183. package/docs/api/interfaces/RBACRoleRevokeParams.md +63 -0
  184. package/docs/api/interfaces/RBACRoleRevokeResult.md +52 -0
  185. package/docs/api/interfaces/RBACRoleValidateParams.md +52 -0
  186. package/docs/api/interfaces/RBACRoleValidateResult.md +63 -0
  187. package/docs/api/interfaces/RBACRolesListParams.md +52 -0
  188. package/docs/api/interfaces/RBACRolesListResult.md +74 -0
  189. package/docs/api/interfaces/RBACSessionTrackParams.md +74 -0
  190. package/docs/api/interfaces/RBACSessionTrackResult.md +52 -0
  191. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  192. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  193. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  194. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  195. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  196. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  197. package/docs/api/interfaces/RouteConfig.md +1 -1
  198. package/docs/api/interfaces/SecureDataContextType.md +1 -1
  199. package/docs/api/interfaces/SecureDataProviderProps.md +1 -1
  200. package/docs/api/interfaces/SessionRestorationLoaderProps.md +15 -2
  201. package/docs/api/interfaces/StorageConfig.md +1 -1
  202. package/docs/api/interfaces/StorageFileInfo.md +1 -1
  203. package/docs/api/interfaces/StorageFileMetadata.md +1 -1
  204. package/docs/api/interfaces/StorageListOptions.md +1 -1
  205. package/docs/api/interfaces/StorageListResult.md +1 -1
  206. package/docs/api/interfaces/StorageUploadOptions.md +1 -1
  207. package/docs/api/interfaces/StorageUploadResult.md +1 -1
  208. package/docs/api/interfaces/StorageUrlOptions.md +1 -1
  209. package/docs/api/interfaces/StyleImport.md +1 -1
  210. package/docs/api/interfaces/SwitchProps.md +1 -1
  211. package/docs/api/interfaces/TabsContentProps.md +1 -1
  212. package/docs/api/interfaces/TabsListProps.md +1 -1
  213. package/docs/api/interfaces/TabsProps.md +1 -1
  214. package/docs/api/interfaces/TabsTriggerProps.md +43 -2
  215. package/docs/api/interfaces/TextareaProps.md +2 -2
  216. package/docs/api/interfaces/ToastActionElement.md +1 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +61 -61
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +13 -13
  220. package/docs/api/interfaces/UseInactivityTrackerOptions.md +1 -1
  221. package/docs/api/interfaces/UseInactivityTrackerReturn.md +1 -1
  222. package/docs/api/interfaces/UsePublicEventLogoOptions.md +87 -0
  223. package/docs/api/interfaces/UsePublicEventLogoReturn.md +81 -0
  224. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  225. package/docs/api/interfaces/UsePublicEventReturn.md +5 -5
  226. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +2 -2
  227. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +1 -1
  228. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +1 -1
  229. package/docs/api/interfaces/UseResolvedScopeOptions.md +2 -2
  230. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  231. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  232. package/docs/api/interfaces/UserEventAccess.md +1 -1
  233. package/docs/api/interfaces/UserMenuProps.md +4 -4
  234. package/docs/api/interfaces/UserProfile.md +7 -7
  235. package/docs/api/modules.md +484 -462
  236. package/docs/api-reference/components.md +186 -15
  237. package/docs/api-reference/deprecated.md +376 -0
  238. package/docs/api-reference/hooks.md +149 -19
  239. package/docs/api-reference/providers.md +61 -6
  240. package/docs/api-reference/rpc-functions.md +397 -0
  241. package/docs/api-reference/types.md +135 -78
  242. package/docs/api-reference/utilities.md +51 -380
  243. package/docs/architecture/README.md +49 -3
  244. package/docs/architecture/database-schema-requirements.md +40 -3
  245. package/docs/architecture/rbac-security-architecture.md +41 -4
  246. package/docs/architecture/services.md +127 -42
  247. package/docs/best-practices/README.md +51 -5
  248. package/docs/best-practices/accessibility.md +32 -3
  249. package/docs/best-practices/common-patterns.md +50 -3
  250. package/docs/best-practices/deployment.md +50 -4
  251. package/docs/best-practices/performance.md +50 -3
  252. package/docs/best-practices/security.md +94 -41
  253. package/docs/best-practices/testing.md +33 -4
  254. package/docs/core-concepts/authentication.md +5 -5
  255. package/docs/core-concepts/events.md +3 -3
  256. package/docs/core-concepts/organisations.md +3 -3
  257. package/docs/core-concepts/permissions.md +3 -3
  258. package/docs/core-concepts/rbac-system.md +5 -5
  259. package/docs/documentation-index.md +30 -8
  260. package/docs/getting-started/documentation-index.md +1 -1
  261. package/docs/getting-started/examples/README.md +7 -5
  262. package/docs/getting-started/examples/basic-auth-app.md +3 -0
  263. package/docs/getting-started/examples/full-featured-app.md +5 -3
  264. package/docs/getting-started/faq.md +6 -6
  265. package/docs/getting-started/installation-guide.md +192 -13
  266. package/docs/getting-started/local-development.md +303 -0
  267. package/docs/getting-started/quick-reference.md +3 -3
  268. package/docs/getting-started/quick-start.md +517 -0
  269. package/docs/implementation-guides/app-layout.md +45 -3
  270. package/docs/implementation-guides/authentication.md +66 -7
  271. package/docs/implementation-guides/component-styling.md +53 -3
  272. package/docs/implementation-guides/data-tables.md +76 -7
  273. package/docs/implementation-guides/datatable-filtering.md +1 -2
  274. package/docs/implementation-guides/datatable-rbac-usage.md +0 -1
  275. package/docs/implementation-guides/dynamic-colors.md +155 -4
  276. package/docs/implementation-guides/file-reference-system.md +72 -3
  277. package/docs/implementation-guides/file-upload-storage.md +72 -3
  278. package/docs/implementation-guides/forms.md +53 -3
  279. package/docs/implementation-guides/inactivity-tracking.md +53 -3
  280. package/docs/implementation-guides/large-datasets.md +1 -1
  281. package/docs/implementation-guides/navigation.md +55 -5
  282. package/docs/implementation-guides/organisation-security.md +72 -3
  283. package/docs/implementation-guides/performance.md +57 -1
  284. package/docs/implementation-guides/permission-enforcement.md +81 -8
  285. package/docs/implementation-guides/public-pages.md +560 -14
  286. package/docs/migration/MIGRATION_GUIDE.md +409 -50
  287. package/docs/migration/README.md +37 -3
  288. package/docs/migration/organisation-context-timing-fix.md +39 -4
  289. package/docs/migration/quick-migration-guide.md +41 -5
  290. package/docs/migration/rbac-migration.md +59 -3
  291. package/docs/migration/service-architecture.md +77 -14
  292. package/docs/rbac/README.md +79 -3
  293. package/docs/rbac/advanced-patterns.md +47 -3
  294. package/docs/rbac/api-reference.md +77 -8
  295. package/docs/rbac/event-based-apps.md +50 -5
  296. package/docs/rbac/examples/rbac-rls-integration-example.md +3 -3
  297. package/docs/rbac/examples.md +39 -3
  298. package/docs/rbac/getting-started.md +63 -4
  299. package/docs/rbac/quick-start.md +57 -5
  300. package/docs/rbac/rbac-rls-integration.md +68 -6
  301. package/docs/rbac/super-admin-guide.md +47 -3
  302. package/docs/rbac/troubleshooting.md +3 -3
  303. package/docs/security/README.md +68 -3
  304. package/docs/security/checklist.md +50 -3
  305. package/docs/standards/01-architecture-standard.md +39 -0
  306. package/docs/standards/02-api-and-rpc-standard.md +39 -0
  307. package/docs/standards/03-component-standard.md +32 -0
  308. package/docs/standards/04-code-style-standard.md +32 -0
  309. package/docs/standards/05-security-standard.md +30 -0
  310. package/docs/standards/06-testing-and-docs-standard.md +29 -0
  311. package/docs/standards/README.md +35 -0
  312. package/docs/styles/README.md +89 -8
  313. package/docs/testing/README.md +175 -24
  314. package/docs/troubleshooting/README.md +50 -3
  315. package/docs/troubleshooting/common-issues.md +271 -5
  316. package/docs/troubleshooting/debugging.md +54 -1
  317. package/docs/troubleshooting/migration.md +54 -1
  318. package/docs/troubleshooting/organisation-context-setup.md +29 -3
  319. package/docs/troubleshooting/styling-issues.md +246 -4
  320. package/{src/components/DataTable/examples → examples/DataTable}/GroupingAggregationExample.tsx +1 -1
  321. package/examples/{components 2/DataTable/HierarchicalActionsExample.tsx → DataTable/HierarchicalActionsExample.tsx} +7 -6
  322. package/examples/{components 2/DataTable/HierarchicalExample.tsx → DataTable/HierarchicalExample.tsx} +8 -6
  323. package/examples/{components 2/DataTable/PerformanceExample.tsx → DataTable/PerformanceExample.tsx} +2 -2
  324. package/examples/{components 2/DataTable/index.ts → DataTable/index.ts} +1 -0
  325. package/{src/components/Dialog/examples → examples/Dialog}/HtmlDialogExample.tsx +3 -3
  326. package/examples/{components 2/Dialog/ScrollableDialogExample.tsx → Dialog/ScrollableDialogExample.tsx} +1 -1
  327. package/{src/components/Dialog/examples → examples/Dialog}/SmartDialogExample.tsx +1 -1
  328. package/examples/{components 2/Dialog/index.ts → Dialog/index.ts} +0 -3
  329. package/examples/{features/public-pages → PublicPages}/CorrectPublicPageImplementation.tsx +52 -17
  330. package/examples/{features/public-pages → PublicPages}/PublicEventPage.tsx +65 -35
  331. package/examples/{features/public-pages → PublicPages}/PublicPageApp.tsx +52 -18
  332. package/examples/{features/public-pages → PublicPages}/PublicPageUsageExample.tsx +28 -15
  333. package/examples/README.md +81 -33
  334. package/examples/index.ts +14 -12
  335. package/examples/{RBAC → rbac}/CompleteRBACExample.tsx +1 -1
  336. package/examples/{features/rbac → rbac}/EventBasedApp.tsx +4 -4
  337. package/examples/{features/rbac → rbac}/PermissionExample.tsx +5 -3
  338. package/package.json +21 -27
  339. package/src/__tests__/helpers/test-utils.tsx +29 -3
  340. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +7 -5
  341. package/src/components/Alert/Alert.test.tsx +2 -2
  342. package/src/components/Alert/Alert.tsx +4 -4
  343. package/src/components/Avatar/Avatar.test.tsx +17 -6
  344. package/src/components/Badge/Badge.test.tsx +1 -1
  345. package/src/components/Badge/Badge.tsx +2 -2
  346. package/src/components/Button/Button.test.tsx +2 -2
  347. package/src/components/Button/Button.tsx +11 -7
  348. package/src/components/Calendar/Calendar.test.tsx +41 -8
  349. package/src/components/Calendar/Calendar.tsx +39 -36
  350. package/src/components/Card/Card.tsx +51 -13
  351. package/src/components/Checkbox/Checkbox.test.tsx +36 -12
  352. package/src/components/DataTable/DataTable.test.tsx +1 -1
  353. package/src/components/DataTable/__tests__/DataTable.comprehensive.test.tsx +13 -7
  354. package/src/components/DataTable/__tests__/DataTable.default-state.test.tsx +14 -42
  355. package/src/components/DataTable/__tests__/DataTable.export.test.tsx +13 -10
  356. package/src/components/DataTable/__tests__/DataTable.grouping-aggregation.test.tsx +14 -11
  357. package/src/components/DataTable/__tests__/DataTable.hooks.test.tsx +4 -2
  358. package/src/components/DataTable/__tests__/DataTable.test.tsx +13 -7
  359. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +13 -10
  360. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +15 -11
  361. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +12 -6
  362. package/src/components/DataTable/__tests__/keyboard.test.tsx +12 -6
  363. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +10 -6
  364. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +1 -1
  365. package/src/components/DataTable/components/DataTableBody.tsx +10 -25
  366. package/src/components/DataTable/components/DataTableCore.tsx +1 -1
  367. package/src/components/DataTable/components/FilterRow.tsx +3 -1
  368. package/src/components/DataTable/components/ImportModal.tsx +1 -1
  369. package/src/components/DataTable/components/VirtualizedDataTable.tsx +9 -9
  370. package/src/components/DataTable/core/ColumnFactory.ts +6 -6
  371. package/src/components/DataTable/core/DataTableContext.tsx +14 -10
  372. package/src/components/DataTable/core/LocalDataAdapter.ts +2 -1
  373. package/src/components/DataTable/core/PluginRegistry.ts +3 -3
  374. package/src/components/DataTable/core/StateManager.ts +12 -11
  375. package/src/components/DataTable/core/__tests__/ActionManager.test.ts +104 -0
  376. package/src/components/DataTable/core/__tests__/DataManager.test.ts +101 -0
  377. package/src/components/DataTable/core/__tests__/LocalDataAdapter.test.ts +84 -0
  378. package/src/components/DataTable/core/__tests__/PluginRegistry.test.ts +102 -0
  379. package/src/components/DataTable/core/__tests__/StateManager.test.ts +104 -0
  380. package/src/components/DataTable/core/interfaces.ts +17 -17
  381. package/src/components/DataTable/hooks/__tests__/useDataTableConfiguration.test.ts +124 -0
  382. package/src/components/DataTable/hooks/__tests__/useDataTableDataPipeline.test.ts +117 -0
  383. package/src/components/DataTable/hooks/__tests__/useDataTablePermissions.test.ts +102 -0
  384. package/src/components/DataTable/hooks/__tests__/useEffectiveColumnOrder.test.ts +53 -0
  385. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +0 -2
  386. package/src/components/DataTable/hooks/useDataTablePermissions.ts +9 -8
  387. package/src/components/DataTable/types.ts +5 -5
  388. package/src/components/DataTable/utils/aggregationUtils.ts +4 -4
  389. package/src/components/DataTable/utils/columnUtils.ts +3 -2
  390. package/src/components/DataTable/utils/debugTools.ts +1 -1
  391. package/src/components/DataTable/utils/exportUtils.ts +6 -6
  392. package/src/components/DataTable/utils/hierarchicalSorting.ts +6 -6
  393. package/src/components/DataTable/utils/hierarchicalUtils.ts +0 -8
  394. package/src/components/DataTable/utils/index.ts +0 -1
  395. package/src/components/DataTable/utils/performanceUtils.ts +9 -4
  396. package/src/components/Dialog/Dialog.test.tsx +49 -27
  397. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +13 -8
  398. package/src/components/EventSelector/EventSelector.test.tsx +60 -12
  399. package/src/components/EventSelector/EventSelector.tsx +38 -15
  400. package/src/components/EventSelector/index.ts +2 -2
  401. package/src/components/FileDisplay/FileDisplay.test.tsx +143 -85
  402. package/src/components/FileDisplay/FileDisplay.tsx +1 -0
  403. package/src/components/FileUpload/FileUpload.test.tsx +532 -152
  404. package/src/components/FileUpload/FileUpload.tsx +43 -8
  405. package/src/components/Footer/Footer.test.tsx +19 -14
  406. package/src/components/Form/Form.test.tsx +96 -14
  407. package/src/components/Form/Form.tsx +210 -1
  408. package/src/components/Form/index.ts +3 -7
  409. package/src/components/Header/Header.test.tsx +24 -17
  410. package/src/components/Header/Header.tsx +3 -1
  411. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +2 -4
  412. package/src/components/Input/Input.test.tsx +61 -36
  413. package/src/components/Label/{__tests__/Label.test.tsx → Label.test.tsx} +2 -2
  414. package/src/components/Label/Label.tsx +2 -3
  415. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +6 -5
  416. package/src/components/LoadingSpinner/LoadingSpinner.tsx +6 -2
  417. package/src/components/LoginForm/LoginForm.test.tsx +14 -13
  418. package/src/components/LoginForm/LoginForm.tsx +1 -1
  419. package/src/components/LoginForm/index.ts +7 -0
  420. package/src/components/NavigationMenu/NavigationMenu.test.tsx +233 -20
  421. package/src/components/NavigationMenu/NavigationMenu.tsx +191 -55
  422. package/src/components/NavigationMenu/index.ts +1 -1
  423. package/src/components/OrganisationSelector/OrganisationSelector.test.tsx +20 -11
  424. package/src/components/OrganisationSelector/OrganisationSelector.tsx +1 -1
  425. package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.integration.test.tsx → PaceAppLayout.integration.test.tsx} +272 -79
  426. package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.performance.test.tsx → PaceAppLayout.performance.test.tsx} +155 -32
  427. package/src/components/PaceAppLayout/{__tests__/PaceAppLayout.security.test.tsx → PaceAppLayout.security.test.tsx} +211 -65
  428. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +498 -210
  429. package/src/components/PaceAppLayout/PaceAppLayout.tsx +63 -64
  430. package/src/components/PaceAppLayout/test-setup.tsx +192 -0
  431. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +193 -39
  432. package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.test.tsx +2 -2
  433. package/src/components/{PasswordReset → PasswordChange}/PasswordChangeForm.tsx +10 -4
  434. package/src/components/PasswordChange/index.ts +2 -0
  435. package/src/components/Progress/Progress.test.tsx +11 -0
  436. package/src/components/Progress/Progress.tsx +1 -1
  437. package/src/components/Progress/index.ts +10 -0
  438. package/src/components/ProtectedRoute/ProtectedRoute.test.tsx +2 -1
  439. package/src/components/PublicLayout/PublicLayout.test.tsx +1210 -0
  440. package/src/components/PublicLayout/PublicPageLayout.tsx +190 -36
  441. package/src/components/PublicLayout/PublicPageProvider.tsx +8 -7
  442. package/src/components/PublicLayout/index.ts +10 -28
  443. package/src/components/Select/Select.test.tsx +7 -7
  444. package/src/components/Select/Select.tsx +277 -11
  445. package/src/components/Select/index.ts +1 -2
  446. package/src/components/SessionRestorationLoader/SessionRestorationLoader.test.tsx +232 -0
  447. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +40 -19
  448. package/src/components/Table/{__tests__/Table.test.tsx → Table.test.tsx} +94 -41
  449. package/src/components/Tabs/Tabs.test.tsx +10 -9
  450. package/src/components/Tabs/Tabs.tsx +61 -33
  451. package/src/components/Textarea/Textarea.test.tsx +31 -18
  452. package/src/components/Toast/Toast.tsx +2 -2
  453. package/src/components/Tooltip/Tooltip.test.tsx +1 -1
  454. package/src/components/UserMenu/UserMenu.test.tsx +7 -6
  455. package/src/components/UserMenu/UserMenu.tsx +2 -2
  456. package/src/components/index.ts +5 -4
  457. package/src/constants/performance.ts +19 -8
  458. package/src/hooks/__tests__/useAppConfig.unit.test.ts +21 -22
  459. package/src/hooks/__tests__/useEvents.unit.test.ts +5 -4
  460. package/src/hooks/__tests__/useOrganisationPermissions.unit.test.tsx +2 -2
  461. package/src/hooks/__tests__/usePermissionCache.simple.test.ts +17 -0
  462. package/src/hooks/__tests__/usePermissionCache.unit.test.ts +16 -11
  463. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +1 -3
  464. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +1 -3
  465. package/src/hooks/__tests__/useRBAC.unit.test.ts +24 -2
  466. package/src/hooks/index.ts +4 -0
  467. package/src/hooks/public/index.ts +2 -0
  468. package/src/hooks/public/usePublicEvent.ts +4 -6
  469. package/src/hooks/public/usePublicRouteParams.ts +1 -1
  470. package/src/hooks/services/useAuth.ts +2 -4
  471. package/src/hooks/services/useCurrentEvent.ts +1 -1
  472. package/src/hooks/useAppConfig.ts +1 -1
  473. package/src/hooks/useDataTablePerformance.ts +2 -2
  474. package/src/hooks/useEventTheme.ts +1 -1
  475. package/src/hooks/useEvents.ts +51 -10
  476. package/src/hooks/useOrganisationPermissions.test.ts +3 -3
  477. package/src/hooks/useOrganisationPermissions.ts +1 -1
  478. package/src/hooks/useOrganisationSecurity.ts +2 -2
  479. package/src/hooks/usePermissionCache.test.ts +9 -9
  480. package/src/hooks/usePermissionCache.ts +2 -2
  481. package/src/index.ts +19 -12
  482. package/src/providers/OrganisationProvider.tsx +73 -9
  483. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +113 -13
  484. package/src/providers/__tests__/AuthProvider.test.tsx +2 -1
  485. package/src/providers/__tests__/EventProvider.test.tsx +24 -15
  486. package/src/providers/__tests__/OrganisationProvider.test.tsx +87 -36
  487. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +80 -24
  488. package/src/providers/index.ts +0 -3
  489. package/src/providers/services/AuthServiceProvider.tsx +2 -17
  490. package/src/providers/services/EventServiceProvider.tsx +11 -16
  491. package/src/providers/services/InactivityServiceProvider.tsx +9 -12
  492. package/src/providers/services/OrganisationServiceProvider.tsx +9 -12
  493. package/src/providers/services/UnifiedAuthProvider.tsx +85 -18
  494. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +11 -4
  495. package/src/rbac/__tests__/scenarios.user-role.test.tsx +105 -21
  496. package/src/rbac/adapters.tsx +1 -1
  497. package/src/rbac/api.ts +20 -4
  498. package/src/rbac/audit-enhanced.ts +47 -2
  499. package/src/rbac/audit.ts +47 -2
  500. package/src/rbac/components/NavigationGuard.tsx +1 -1
  501. package/src/rbac/components/NavigationProvider.test.tsx +7 -6
  502. package/src/rbac/components/NavigationProvider.tsx +1 -1
  503. package/src/rbac/components/PagePermissionGuard.tsx +1 -1
  504. package/src/rbac/components/PagePermissionProvider.test.tsx +7 -6
  505. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  506. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  507. package/src/rbac/components/RoleBasedRouter.tsx +1 -1
  508. package/src/rbac/components/SecureDataProvider.test.tsx +7 -6
  509. package/src/rbac/components/SecureDataProvider.tsx +1 -1
  510. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +6 -6
  511. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +11 -10
  512. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +10 -11
  513. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +19 -15
  514. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +13 -12
  515. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +19 -15
  516. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +18 -18
  517. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +11 -10
  518. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +8 -7
  519. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +10 -11
  520. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +48 -19
  521. package/src/rbac/hooks/__tests__/useSecureSupabase.test.ts +476 -0
  522. package/src/rbac/hooks/index.ts +3 -0
  523. package/src/rbac/hooks/usePermissions.ts +31 -85
  524. package/src/rbac/hooks/useRBAC.test.ts +13 -1
  525. package/src/rbac/hooks/useRBAC.ts +13 -67
  526. package/src/rbac/hooks/useResolvedScope.ts +11 -0
  527. package/src/rbac/hooks/useSecureSupabase.ts +308 -0
  528. package/src/rbac/index.ts +3 -0
  529. package/src/rbac/secureClient.ts +53 -6
  530. package/src/rbac/security.ts +37 -1
  531. package/src/{types/rbac-functions.ts → rbac/types/functions.ts} +30 -30
  532. package/src/rbac/types.ts +3 -2
  533. package/src/services/AuthService.ts +33 -25
  534. package/src/services/EventService.ts +57 -31
  535. package/src/services/InactivityService.ts +33 -53
  536. package/src/services/OrganisationService.ts +36 -40
  537. package/src/services/__tests__/AuthService.restoreSession.test.ts +6 -2
  538. package/src/services/__tests__/EventService.test.ts +67 -33
  539. package/src/services/interfaces/IEventService.ts +1 -1
  540. package/src/styles/core.css +2 -2
  541. package/src/styles/index.ts +1 -5
  542. package/src/types/__tests__/guards.test.ts +1 -1
  543. package/src/types/__tests__/type-validation.test.ts +0 -1
  544. package/src/types/auth.ts +42 -2
  545. package/src/types/core.ts +251 -0
  546. package/src/types/database.ts +11 -496
  547. package/src/types/event.ts +102 -0
  548. package/src/types/file-reference.ts +6 -4
  549. package/src/types/guards.ts +2 -1
  550. package/src/types/index.ts +48 -14
  551. package/src/types/lodash.debounce.d.ts +15 -0
  552. package/src/types/organisation.ts +14 -10
  553. package/src/types/supabase.ts +15 -17
  554. package/src/utils/__tests__/secureErrors.unit.test.ts +1 -1
  555. package/src/utils/__tests__/validationUtils.unit.test.ts +0 -29
  556. package/src/utils/app/appNameResolver.ts +1 -1
  557. package/src/utils/dynamic/dynamicUtils.ts +3 -2
  558. package/src/utils/file-reference/index.ts +25 -6
  559. package/src/utils/security/secureErrors.ts +1 -1
  560. package/src/utils/validation/index.ts +6 -12
  561. package/src/utils/validation/validationUtils.ts +0 -13
  562. package/dist/UnifiedAuthProvider-BMJAP6Z7.js +0 -16
  563. package/dist/auth-DReDSLq9.d.ts +0 -16
  564. package/dist/chunk-56XJ3TU6.js +0 -11
  565. package/dist/chunk-56XJ3TU6.js.map +0 -1
  566. package/dist/chunk-6HLVGAZG.js.map +0 -1
  567. package/dist/chunk-7QCC6MCP.js +0 -288
  568. package/dist/chunk-BESYRHQM.js.map +0 -1
  569. package/dist/chunk-BJPBT3CU.js +0 -21
  570. package/dist/chunk-BJPBT3CU.js.map +0 -1
  571. package/dist/chunk-BVYWGZVV.js.map +0 -1
  572. package/dist/chunk-CPTUD43C.js.map +0 -1
  573. package/dist/chunk-CX5M4ZAG.js.map +0 -1
  574. package/dist/chunk-ERGKJX4D.js +0 -15
  575. package/dist/chunk-ERGKJX4D.js.map +0 -1
  576. package/dist/chunk-ERISIBYU.js.map +0 -1
  577. package/dist/chunk-GQA2LIAE.js.map +0 -1
  578. package/dist/chunk-JISYG63F.js +0 -70
  579. package/dist/chunk-JISYG63F.js.map +0 -1
  580. package/dist/chunk-MSHEVJXS.js +0 -27
  581. package/dist/chunk-MSHEVJXS.js.map +0 -1
  582. package/dist/chunk-N5YCCUG5.js.map +0 -1
  583. package/dist/chunk-ONI7Y733.js.map +0 -1
  584. package/dist/chunk-OWAG3GSU.js.map +0 -1
  585. package/dist/chunk-P6UUHOIF.js.map +0 -1
  586. package/dist/chunk-PKW27QVS.js +0 -61
  587. package/dist/chunk-PKW27QVS.js.map +0 -1
  588. package/dist/chunk-Q5QRDWKI.js.map +0 -1
  589. package/dist/chunk-S5OFRT4M.js.map +0 -1
  590. package/dist/chunk-SBVILCCA.js.map +0 -1
  591. package/dist/chunk-WM26XK7I.js +0 -2432
  592. package/dist/chunk-WM26XK7I.js.map +0 -1
  593. package/dist/chunk-XDNLUEXI.js +0 -138
  594. package/dist/chunk-XJ2HZOBU.js.map +0 -1
  595. package/dist/chunk-ZZ2SS7NI.js +0 -237
  596. package/dist/chunk-ZZ2SS7NI.js.map +0 -1
  597. package/dist/database-C6jy7EOu.d.ts +0 -500
  598. package/dist/organisation-D6qRDtbF.d.ts +0 -93
  599. package/dist/schema-DTDZQe2u.d.ts +0 -28
  600. package/dist/unified-DQ4VcT7H.d.ts +0 -198
  601. package/dist/useInactivityTracker-TO6ZOF35.js +0 -11
  602. package/dist/validation.d.ts +0 -47
  603. package/dist/validation.js +0 -24
  604. package/dist/validation.js.map +0 -1
  605. package/docs/DOCUMENTATION_AUDIT.md +0 -172
  606. package/docs/DOCUMENTATION_STANDARD.md +0 -137
  607. package/docs/api/classes/PublicErrorBoundary.md +0 -132
  608. package/docs/api/interfaces/EventLogoProps.md +0 -152
  609. package/docs/api/interfaces/PublicErrorBoundaryProps.md +0 -94
  610. package/docs/api/interfaces/PublicErrorBoundaryState.md +0 -68
  611. package/docs/api/interfaces/PublicLoadingSpinnerProps.md +0 -86
  612. package/docs/architecture/rpc-function-standards.md +0 -1106
  613. package/docs/getting-started/consuming-app-vite-config.md +0 -239
  614. package/docs/implementation-guides/event-theming-summary.md +0 -226
  615. package/docs/implementation-guides/public-pages-advanced.md +0 -1038
  616. package/docs/migration/v0.4.15-tailwind-scanning.md +0 -278
  617. package/docs/migration/v0.4.16-css-first-approach.md +0 -312
  618. package/docs/migration/v0.4.17-source-path-fix.md +0 -235
  619. package/docs/rbac/RBAC_EVENT_CONTEXT_LOADING.md +0 -222
  620. package/docs/rbac/RBAC_LOGIN_SAFETY_FIX.md +0 -95
  621. package/docs/rbac/RBAC_V0.5.147_FIX.md +0 -117
  622. package/docs/rbac/README-rbac-rls-integration.md +0 -374
  623. package/docs/styles/usage.md +0 -227
  624. package/docs/testing/visual-testing.md +0 -120
  625. package/docs/troubleshooting/DEBUG_NETWORK_ERROR.md +0 -152
  626. package/docs/troubleshooting/FIX_SUPABASE_CORS.md +0 -184
  627. package/docs/troubleshooting/cake-page-permission-guard-issue-summary.md +0 -193
  628. package/docs/troubleshooting/database-view-compatibility.md +0 -125
  629. package/docs/troubleshooting/react-hooks-issue-analysis.md +0 -172
  630. package/docs/troubleshooting/tailwind-content-scanning.md +0 -219
  631. package/examples/RBAC/EventBasedApp.tsx +0 -239
  632. package/examples/RBAC/PermissionExample.tsx +0 -151
  633. package/examples/STRUCTURE.md +0 -125
  634. package/examples/components 2/Dialog/BasicHtmlTest.tsx +0 -55
  635. package/examples/components 2/Dialog/DebugHtmlExample.tsx +0 -68
  636. package/examples/components 2/Dialog/HtmlDialogExample.tsx +0 -202
  637. package/examples/components 2/Dialog/SimpleHtmlTest.tsx +0 -61
  638. package/examples/components 2/Dialog/SmartDialogExample.tsx +0 -322
  639. package/examples/components 2/index.ts +0 -11
  640. package/examples/features/index.ts +0 -12
  641. package/examples/features/rbac/CompleteRBACExample.tsx +0 -324
  642. package/examples/features/rbac/index.ts +0 -13
  643. package/examples/public-pages/CorrectPublicPageImplementation.tsx +0 -301
  644. package/examples/public-pages/PublicEventPage.tsx +0 -274
  645. package/examples/public-pages/PublicPageApp.tsx +0 -308
  646. package/examples/public-pages/PublicPageUsageExample.tsx +0 -216
  647. package/examples/public-pages/index.ts +0 -14
  648. package/src/__tests__/TEST_STANDARD.md +0 -1008
  649. package/src/components/Checkbox/__mocks__/Checkbox.tsx +0 -2
  650. package/src/components/DataTable/examples/HierarchicalActionsExample.tsx +0 -421
  651. package/src/components/DataTable/examples/HierarchicalExample.tsx +0 -475
  652. package/src/components/DataTable/examples/InitialPageSizeExample.tsx +0 -177
  653. package/src/components/DataTable/examples/PerformanceExample.tsx +0 -506
  654. package/src/components/DataTable/examples/__tests__/HierarchicalActionsExample.test.tsx +0 -316
  655. package/src/components/DataTable/examples/__tests__/HierarchicalExample.test.tsx +0 -45
  656. package/src/components/DataTable/examples/__tests__/InitialPageSizeExample.test.tsx +0 -211
  657. package/src/components/DataTable/examples/__tests__/PerformanceExample.test.tsx +0 -126
  658. package/src/components/Dialog/README.md +0 -804
  659. package/src/components/Dialog/examples/BasicHtmlTest.tsx +0 -55
  660. package/src/components/Dialog/examples/DebugHtmlExample.tsx +0 -68
  661. package/src/components/Dialog/examples/ScrollableDialogExample.tsx +0 -290
  662. package/src/components/Dialog/examples/SimpleHtmlTest.tsx +0 -61
  663. package/src/components/Dialog/examples/__tests__/HtmlDialogExample.test.tsx +0 -71
  664. package/src/components/Dialog/examples/__tests__/SimpleHtmlTest.test.tsx +0 -122
  665. package/src/components/Dialog/examples/__tests__/SmartDialogExample.unit.test.tsx +0 -147
  666. package/src/components/Dialog/utils/__tests__/safeHtml.unit.test.ts +0 -611
  667. package/src/components/Dialog/utils/safeHtml.ts +0 -185
  668. package/src/components/EventSelector/types.ts +0 -79
  669. package/src/components/Form/FormErrorSummary.tsx +0 -113
  670. package/src/components/Form/FormField.tsx +0 -249
  671. package/src/components/Form/FormFieldset.tsx +0 -127
  672. package/src/components/Form/FormLiveRegion.tsx +0 -198
  673. package/src/components/Input/__mocks__/Input.tsx +0 -2
  674. package/src/components/NavigationMenu/types.ts +0 -85
  675. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.accessibility.test.tsx +0 -326
  676. package/src/components/PaceAppLayout/__tests__/PaceAppLayout.unit.test.tsx +0 -1078
  677. package/src/components/PasswordReset/PasswordResetForm.test.tsx +0 -597
  678. package/src/components/PasswordReset/PasswordResetForm.tsx +0 -201
  679. package/src/components/PasswordReset/index.ts +0 -2
  680. package/src/components/ProtectedRoute/README.md +0 -164
  681. package/src/components/PublicLayout/EventLogo.tsx +0 -175
  682. package/src/components/PublicLayout/PublicErrorBoundary.tsx +0 -282
  683. package/src/components/PublicLayout/PublicLoadingSpinner.tsx +0 -216
  684. package/src/components/PublicLayout/PublicPageContextChecker.tsx +0 -131
  685. package/src/components/PublicLayout/PublicPageDebugger.tsx +0 -104
  686. package/src/components/PublicLayout/PublicPageDiagnostic.tsx +0 -162
  687. package/src/components/PublicLayout/PublicPageFooter.tsx +0 -124
  688. package/src/components/PublicLayout/PublicPageHeader.tsx +0 -209
  689. package/src/components/PublicLayout/__tests__/PublicErrorBoundary.test.tsx +0 -449
  690. package/src/components/PublicLayout/__tests__/PublicLoadingSpinner.test.tsx +0 -393
  691. package/src/components/PublicLayout/__tests__/PublicPageContextChecker.test.tsx +0 -192
  692. package/src/components/PublicLayout/__tests__/PublicPageFooter.test.tsx +0 -351
  693. package/src/components/PublicLayout/__tests__/PublicPageHeader.test.tsx +0 -402
  694. package/src/components/PublicLayout/__tests__/PublicPageLayout.test.tsx +0 -460
  695. package/src/components/PublicLayout/__tests__/PublicPageProvider.test.tsx +0 -313
  696. package/src/components/Select/hooks.ts +0 -289
  697. package/src/hooks/useCounter.test.ts +0 -131
  698. package/src/hooks/useDebounce.test.ts +0 -375
  699. package/src/providers/AuthProvider.tsx +0 -15
  700. package/src/providers/EventProvider.tsx +0 -16
  701. package/src/providers/InactivityProvider.tsx +0 -15
  702. package/src/providers/OrganisationProvider.context.test.tsx +0 -169
  703. package/src/providers/UnifiedAuthProvider.tsx +0 -15
  704. package/src/types/theme.ts +0 -6
  705. package/src/types/unified.ts +0 -265
  706. package/src/utils/appConfig.ts +0 -47
  707. package/src/utils/appIdResolver.test.ts +0 -499
  708. package/src/utils/appIdResolver.ts +0 -130
  709. package/src/utils/appNameResolver.simple.test.ts +0 -212
  710. package/src/utils/appNameResolver.test.ts +0 -121
  711. package/src/utils/appNameResolver.ts +0 -191
  712. package/src/utils/audit.ts +0 -127
  713. package/src/utils/auth-utils.ts +0 -96
  714. package/src/utils/bundleAnalysis.ts +0 -129
  715. package/src/utils/debugLogger.ts +0 -67
  716. package/src/utils/deviceFingerprint.ts +0 -215
  717. package/src/utils/dynamicUtils.ts +0 -105
  718. package/src/utils/file-reference.test.ts +0 -788
  719. package/src/utils/file-reference.ts +0 -519
  720. package/src/utils/formatDate.test.ts +0 -237
  721. package/src/utils/formatting.ts +0 -170
  722. package/src/utils/lazyLoad.tsx +0 -44
  723. package/src/utils/logger.ts +0 -179
  724. package/src/utils/organisationContext.test.ts +0 -322
  725. package/src/utils/organisationContext.ts +0 -153
  726. package/src/utils/performanceBenchmark.ts +0 -64
  727. package/src/utils/performanceBudgets.ts +0 -110
  728. package/src/utils/permissionTypes.ts +0 -37
  729. package/src/utils/permissionUtils.test.ts +0 -393
  730. package/src/utils/permissionUtils.ts +0 -34
  731. package/src/utils/sanitization.ts +0 -264
  732. package/src/utils/schemaUtils.ts +0 -37
  733. package/src/utils/secureDataAccess.test.ts +0 -711
  734. package/src/utils/secureDataAccess.ts +0 -377
  735. package/src/utils/secureErrors.ts +0 -79
  736. package/src/utils/security.ts +0 -156
  737. package/src/utils/securityMonitor.ts +0 -45
  738. package/src/utils/sessionTracking.ts +0 -126
  739. package/src/utils/validation.ts +0 -111
  740. package/src/utils/validationUtils.ts +0 -120
  741. package/src/validation/index.ts +0 -12
  742. /package/dist/{DataTable-4VSEJQ7D.js.map → DataTable-QAB34V6K.js.map} +0 -0
  743. /package/dist/{UnifiedAuthProvider-BMJAP6Z7.js.map → UnifiedAuthProvider-7F6T4B6K.js.map} +0 -0
  744. /package/dist/{api-45XYYO2A.js.map → api-ROMBCNKU.js.map} +0 -0
  745. /package/dist/{audit-64X3VJXB.js.map → audit-WRS3KJKI.js.map} +0 -0
  746. /package/dist/{chunk-PLDDJCW6.js.map → chunk-7D4SUZUM.js.map} +0 -0
  747. /package/dist/{useInactivityTracker-TO6ZOF35.js.map → chunk-KQCRWDSA.js.map} +0 -0
  748. /package/examples/{components 2/DataTable → DataTable}/InitialPageSizeExample.tsx +0 -0
  749. /package/examples/{features/public-pages → PublicPages}/index.ts +0 -0
  750. /package/examples/{RBAC → rbac}/index.ts +0 -0
@@ -1,70 +0,0 @@
1
- // src/utils/validation.ts
2
- function isValidEmail(email) {
3
- const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
4
- return emailPattern.test(email);
5
- }
6
- function isEmpty(value) {
7
- return value === null || value === void 0 || value.trim() === "";
8
- }
9
- function isStrongPassword(password) {
10
- const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).{8,}$/;
11
- return passwordPattern.test(password);
12
- }
13
- function isValidUrl(url) {
14
- try {
15
- new URL(url);
16
- return true;
17
- } catch {
18
- return false;
19
- }
20
- }
21
- function isValidDate(dateStr) {
22
- const date = new Date(dateStr);
23
- return !isNaN(date.getTime());
24
- }
25
- function isWithinRange(value, min, max) {
26
- return value >= min && value <= max;
27
- }
28
- function matchesPattern(value, pattern) {
29
- return pattern.test(value);
30
- }
31
- function deepMerge(target, source) {
32
- const output = { ...target };
33
- if (isObject(target) && isObject(source)) {
34
- Object.keys(source).forEach((key) => {
35
- if (isObject(source[key])) {
36
- if (!(key in target)) {
37
- Object.assign(output, { [key]: source[key] });
38
- } else {
39
- const targetKey = key;
40
- const targetValue = target[targetKey];
41
- if (isObject(targetValue)) {
42
- output[targetKey] = deepMerge(
43
- targetValue,
44
- source[key]
45
- );
46
- }
47
- }
48
- } else {
49
- Object.assign(output, { [key]: source[key] });
50
- }
51
- });
52
- }
53
- return output;
54
- }
55
- function isObject(item) {
56
- return item !== null && typeof item === "object" && !Array.isArray(item);
57
- }
58
-
59
- export {
60
- isValidEmail,
61
- isEmpty,
62
- isStrongPassword,
63
- isValidUrl,
64
- isValidDate,
65
- isWithinRange,
66
- matchesPattern,
67
- deepMerge,
68
- isObject
69
- };
70
- //# sourceMappingURL=chunk-JISYG63F.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/validation.ts"],"sourcesContent":["/**\n * @file Internal utilities for validation module\n * @internal This file contains implementation details that should not be used directly\n */\n\n/**\n * Utility functions for validating data in the application\n */\n\n/**\n * Check if a string is a valid email\n */\nexport function isValidEmail(email: string): boolean {\n const emailPattern = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n return emailPattern.test(email);\n}\n\n/**\n * Check if a string is empty (either null, undefined, or just whitespace)\n */\nexport function isEmpty(value: string | null | undefined): boolean {\n return value === null || value === undefined || value.trim() === '';\n}\n\n/**\n * Check if a password meets minimum requirements\n */\nexport function isStrongPassword(password: string): boolean {\n // Minimum 8 characters, at least one uppercase, one lowercase, one number\n const passwordPattern = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{8,}$/;\n return passwordPattern.test(password);\n}\n\n/**\n * Check if a URL is valid\n */\nexport function isValidUrl(url: string): boolean {\n try {\n new URL(url);\n return true;\n } catch {\n return false;\n }\n}\n\n/**\n * Check if a date string is valid\n */\nexport function isValidDate(dateStr: string): boolean {\n const date = new Date(dateStr);\n return !isNaN(date.getTime());\n}\n\n/**\n * Check if a value is within a range\n */\nexport function isWithinRange(value: number, min: number, max: number): boolean {\n return value >= min && value <= max;\n}\n\n/**\n * Check if a value matches a specific pattern\n */\nexport function matchesPattern(value: string, pattern: RegExp): boolean {\n return pattern.test(value);\n}\n\n/**\n * Utility function to deep merge objects for schema combination\n * @internal\n */\nexport function deepMerge<T extends Record<string, unknown>>(\n target: T, \n source: Record<string, unknown>\n): T {\n const output = { ...target };\n \n if (isObject(target) && isObject(source)) {\n Object.keys(source).forEach(key => {\n if (isObject(source[key])) {\n if (!(key in target)) {\n Object.assign(output, { [key]: source[key] });\n } else {\n // Use a type assertion to safely handle the indexing\n const targetKey = key as keyof typeof target;\n const targetValue = target[targetKey];\n \n if (isObject(targetValue)) {\n // Safe cast using type assertion\n output[targetKey] = deepMerge(\n targetValue as Record<string, unknown>,\n source[key] as Record<string, unknown>\n ) as unknown as T[keyof T];\n }\n }\n } else {\n Object.assign(output, { [key]: source[key] });\n }\n });\n }\n \n return output as T;\n}\n\n/**\n * Type guard to check if a value is a plain object\n * @internal\n */\nexport function isObject(item: unknown): item is Record<string, unknown> {\n return item !== null && typeof item === 'object' && !Array.isArray(item);\n}\n"],"mappings":";AAYO,SAAS,aAAa,OAAwB;AACnD,QAAM,eAAe;AACrB,SAAO,aAAa,KAAK,KAAK;AAChC;AAKO,SAAS,QAAQ,OAA2C;AACjE,SAAO,UAAU,QAAQ,UAAU,UAAa,MAAM,KAAK,MAAM;AACnE;AAKO,SAAS,iBAAiB,UAA2B;AAE1D,QAAM,kBAAkB;AACxB,SAAO,gBAAgB,KAAK,QAAQ;AACtC;AAKO,SAAS,WAAW,KAAsB;AAC/C,MAAI;AACF,QAAI,IAAI,GAAG;AACX,WAAO;AAAA,EACT,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,YAAY,SAA0B;AACpD,QAAM,OAAO,IAAI,KAAK,OAAO;AAC7B,SAAO,CAAC,MAAM,KAAK,QAAQ,CAAC;AAC9B;AAKO,SAAS,cAAc,OAAe,KAAa,KAAsB;AAC9E,SAAO,SAAS,OAAO,SAAS;AAClC;AAKO,SAAS,eAAe,OAAe,SAA0B;AACtE,SAAO,QAAQ,KAAK,KAAK;AAC3B;AAMO,SAAS,UACd,QACA,QACG;AACH,QAAM,SAAS,EAAE,GAAG,OAAO;AAE3B,MAAI,SAAS,MAAM,KAAK,SAAS,MAAM,GAAG;AACxC,WAAO,KAAK,MAAM,EAAE,QAAQ,SAAO;AACjC,UAAI,SAAS,OAAO,GAAG,CAAC,GAAG;AACzB,YAAI,EAAE,OAAO,SAAS;AACpB,iBAAO,OAAO,QAAQ,EAAE,CAAC,GAAG,GAAG,OAAO,GAAG,EAAE,CAAC;AAAA,QAC9C,OAAO;AAEL,gBAAM,YAAY;AAClB,gBAAM,cAAc,OAAO,SAAS;AAEpC,cAAI,SAAS,WAAW,GAAG;AAEzB,mBAAO,SAAS,IAAI;AAAA,cAClB;AAAA,cACA,OAAO,GAAG;AAAA,YACZ;AAAA,UACF;AAAA,QACF;AAAA,MACF,OAAO;AACL,eAAO,OAAO,QAAQ,EAAE,CAAC,GAAG,GAAG,OAAO,GAAG,EAAE,CAAC;AAAA,MAC9C;AAAA,IACF,CAAC;AAAA,EACH;AAEA,SAAO;AACT;AAMO,SAAS,SAAS,MAAgD;AACvE,SAAO,SAAS,QAAQ,OAAO,SAAS,YAAY,CAAC,MAAM,QAAQ,IAAI;AACzE;","names":[]}
@@ -1,27 +0,0 @@
1
- import {
2
- UnifiedAuthProvider,
3
- init_UnifiedAuthProvider,
4
- useUnifiedAuth
5
- } from "./chunk-WM26XK7I.js";
6
- import {
7
- __esm,
8
- __export
9
- } from "./chunk-PLDDJCW6.js";
10
-
11
- // src/providers/UnifiedAuthProvider.tsx
12
- var UnifiedAuthProvider_exports = {};
13
- __export(UnifiedAuthProvider_exports, {
14
- UnifiedAuthProvider: () => UnifiedAuthProvider,
15
- useUnifiedAuth: () => useUnifiedAuth
16
- });
17
- var init_UnifiedAuthProvider2 = __esm({
18
- "src/providers/UnifiedAuthProvider.tsx"() {
19
- init_UnifiedAuthProvider();
20
- }
21
- });
22
-
23
- export {
24
- UnifiedAuthProvider_exports,
25
- init_UnifiedAuthProvider2 as init_UnifiedAuthProvider
26
- };
27
- //# sourceMappingURL=chunk-MSHEVJXS.js.map
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/providers/UnifiedAuthProvider.tsx"],"sourcesContent":["/**\n * @file Re-export for UnifiedAuthProvider\n * @package @jmruthers/pace-core\n * @module Providers\n * @since 0.1.0\n * \n * Re-exports the service-based UnifiedAuthProvider for backward compatibility.\n * This file exists to maintain existing import paths while the actual implementation\n * has moved to the service architecture.\n */\n\nexport { UnifiedAuthProvider, useUnifiedAuth } from './services/UnifiedAuthProvider';\nexport type { UnifiedAuthProviderProps, UnifiedAuthContextType } from './services/UnifiedAuthProvider';\nexport type { UserEventAccess } from './services/UnifiedAuthProvider';\n\n"],"mappings":";;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAAAA,4BAAA;AAAA;AAWA;AAAA;AAAA;","names":["init_UnifiedAuthProvider"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/hooks/useOrganisationSecurity.ts","../src/hooks/useOrganisationPermissions.ts","../src/hooks/public/usePublicEvent.ts","../src/hooks/public/usePublicRouteParams.ts"],"sourcesContent":["/**\n * @file Organisation Security Hook\n * @package @jmruthers/pace-core\n * @module Hooks/OrganisationSecurity\n * @since 0.4.0\n *\n * Security-focused hook for organisation access validation and super admin functionality.\n * Provides utilities for validating user access to organisations and checking permissions.\n */\n\nimport { useCallback, useMemo, useEffect, useState } from 'react';\nimport { useUnifiedAuth } from '../providers';\nimport { useOrganisations } from './useOrganisations';\n// Legacy useRBAC hook removed - use new RBAC system instead\nimport type { OrganisationSecurityError, SuperAdminContext } from '../types/organisation';\nimport type { Permission } from '../rbac/types';\nimport { logger } from '../utils/core/logger';\n\nexport interface OrganisationSecurityHook {\n // Super admin context\n superAdminContext: SuperAdminContext;\n \n // Access validation\n validateOrganisationAccess: (orgId: string) => Promise<boolean>;\n hasMinimumRole: (minRole: string, orgId?: string) => boolean;\n canAccessChildOrganisations: (orgId?: string) => boolean;\n \n // Permission checks\n hasPermission: (permission: string, orgId?: string) => Promise<boolean>;\n getUserPermissions: (orgId?: string) => Promise<string[]>;\n \n // Audit logging\n logOrganisationAccess: (action: string, details?: any) => Promise<void>;\n \n // Security utilities\n ensureOrganisationAccess: (orgId: string) => Promise<void>;\n validateUserAccess: (userId: string, orgId: string) => Promise<boolean>;\n}\n\nexport const useOrganisationSecurity = (): OrganisationSecurityHook => {\n const { user, session, supabase } = useUnifiedAuth();\n const { selectedOrganisation, getUserRole, validateOrganisationAccess: validateAccess } = useOrganisations();\n \n // Super admin status - query database for security (user_metadata can be spoofed)\n const [isSuperAdmin, setIsSuperAdmin] = useState<boolean>(false);\n const [isCheckingSuperAdmin, setIsCheckingSuperAdmin] = useState(false);\n\n // Check super admin status from database\n useEffect(() => {\n if (!user || !session || !supabase) {\n setIsSuperAdmin(false);\n return;\n }\n\n const checkSuperAdmin = async () => {\n setIsCheckingSuperAdmin(true);\n try {\n const now = new Date().toISOString();\n const { data, error } = await supabase\n .from('rbac_global_roles')\n .select('role')\n .eq('user_id', user.id)\n .eq('role', 'super_admin')\n .lte('valid_from', now)\n .or(`valid_to.is.null,valid_to.gte.${now}`)\n .limit(1);\n\n setIsSuperAdmin(!error && data && data.length > 0);\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Error checking super admin status:', error);\n setIsSuperAdmin(false);\n } finally {\n setIsCheckingSuperAdmin(false);\n }\n };\n\n checkSuperAdmin();\n }, [user, session, supabase]);\n\n // Super admin context\n const superAdminContext = useMemo((): SuperAdminContext => {\n return {\n isSuperAdmin,\n hasGlobalAccess: isSuperAdmin,\n canManageAllOrganisations: isSuperAdmin\n };\n }, [isSuperAdmin]);\n\n // Validate organisation access with database check\n const validateOrganisationAccess = useCallback(async (orgId: string): Promise<boolean> => {\n if (!user || !session || !supabase) return false;\n \n try {\n // Super admin has access to all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Check organisation membership using consolidated rbac_organisation_roles table\n const { data, error } = await supabase\n .from('rbac_organisation_roles')\n .select('id')\n .eq('user_id', user.id)\n .eq('organisation_id', orgId)\n .eq('status', 'active')\n .is('revoked_at', null)\n .in('role', ['org_admin', 'leader', 'member']) // Only actual members, not supporters\n .single();\n\n if (error) {\n logger.error('useOrganisationSecurity', 'Error validating organisation access:', error);\n return false;\n }\n\n return !!data;\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception validating organisation access:', error);\n return false;\n }\n }, [user, session, supabase, superAdminContext.isSuperAdmin]);\n\n // Check if user has minimum role\n const hasMinimumRole = useCallback((minRole: string, orgId?: string): boolean => {\n // Super admin has all roles\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n const roleHierarchy = ['supporter', 'member', 'leader', 'org_admin'];\n \n const userRoleIndex = roleHierarchy.indexOf(userRole);\n const minRoleIndex = roleHierarchy.indexOf(minRole);\n \n return userRoleIndex >= minRoleIndex;\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check if user can access child organisations\n const canAccessChildOrganisations = useCallback((orgId?: string): boolean => {\n // Super admin can access all organisations\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId) return false;\n\n const userRole = getUserRole(targetOrgId);\n return userRole === 'org_admin';\n }, [selectedOrganisation, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Check specific permission using the new RBAC system\n const hasPermission = useCallback(async (permission: string, orgId?: string): Promise<boolean> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return false;\n\n try {\n // Use the new RBAC system\n const { isPermitted } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n return await isPermitted({\n userId: user.id,\n scope,\n permission: permission as Permission\n });\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception checking permission:', error);\n return false;\n }\n }, [selectedOrganisation, user, superAdminContext.isSuperAdmin]);\n\n // Get user's permissions for organisation using the new RBAC system\n const getUserPermissions = useCallback(async (orgId?: string): Promise<string[]> => {\n // Super admin has all permissions\n if (superAdminContext.isSuperAdmin) {\n return ['*']; // All permissions\n }\n\n const targetOrgId = orgId || selectedOrganisation?.id;\n if (!targetOrgId || !user) return [];\n\n try {\n // Use the new RBAC system\n const { getPermissionMap } = await import('../rbac/api');\n \n const scope = {\n organisationId: targetOrgId,\n eventId: user.user_metadata?.eventId || user.app_metadata?.eventId,\n appId: user.user_metadata?.appId || user.app_metadata?.appId,\n };\n\n const permissionMap = await getPermissionMap({\n userId: user.id,\n scope\n });\n \n // Flatten all permissions from all pages\n const allPermissions = Object.entries(permissionMap)\n .filter(([, allowed]) => allowed)\n .map(([permission]) => permission);\n return [...new Set(allPermissions)]; // Remove duplicates\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception getting user permissions:', error);\n return [];\n }\n }, [selectedOrganisation, user, getUserRole, superAdminContext.isSuperAdmin]);\n\n // Log organisation access for audit using the new RBAC audit system\n const logOrganisationAccess = useCallback(async (action: string, details?: any): Promise<void> => {\n if (!user || !selectedOrganisation) return;\n\n try {\n // Use the new RBAC audit system - only if we have a valid organisation ID\n if (selectedOrganisation.id) {\n const { emitAuditEvent } = await import('../rbac/audit');\n \n await emitAuditEvent({\n type: 'permission_check',\n userId: user.id,\n organisationId: selectedOrganisation.id,\n permission: action,\n decision: true, // Assume access was granted if we're logging it\n source: 'api',\n duration_ms: 0, // No actual permission check performed here\n metadata: details || {}\n });\n }\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Error logging organisation access:', error);\n }\n }, [user, selectedOrganisation]);\n\n // Ensure organisation access (throws if no access)\n const ensureOrganisationAccess = useCallback(async (orgId: string): Promise<void> => {\n const hasAccess = await validateOrganisationAccess(orgId);\n \n if (!hasAccess) {\n const error = new Error(`User does not have access to organisation ${orgId}`) as OrganisationSecurityError;\n error.name = 'OrganisationSecurityError';\n error.code = 'ACCESS_DENIED';\n error.organisationId = orgId;\n error.userId = user?.id;\n throw error;\n }\n }, [validateOrganisationAccess, user]);\n\n // Validate user access (for admin functions)\n const validateUserAccess = useCallback(async (userId: string, orgId: string): Promise<boolean> => {\n if (!supabase) return false;\n\n try {\n // Super admin can validate any user\n if (superAdminContext.isSuperAdmin) {\n return true;\n }\n\n // Regular users can only validate their own access\n if (userId !== user?.id) {\n return false;\n }\n\n return await validateOrganisationAccess(orgId);\n } catch (error) {\n logger.error('useOrganisationSecurity', 'Exception validating user access:', error);\n return false;\n }\n }, [supabase, superAdminContext.isSuperAdmin, user, validateOrganisationAccess]);\n\n return {\n superAdminContext,\n validateOrganisationAccess,\n hasMinimumRole,\n canAccessChildOrganisations,\n hasPermission,\n getUserPermissions,\n logOrganisationAccess,\n ensureOrganisationAccess,\n validateUserAccess\n };\n}; ","/**\n * @file useOrganisationPermissions Hook\n * @package @jmruthers/pace-core\n * @module Hooks/useOrganisationPermissions\n * @since 0.4.0\n *\n * Hook for managing organisation-specific permissions and role validation.\n * Provides secure access to user's role and permissions within organisations.\n *\n * @example\n * ```tsx\n * function OrganisationComponent() {\n * const { \n * isOrgAdmin, \n * canManageMembers,\n * userRole,\n * hasOrganisationAccess\n * } = useOrganisationPermissions();\n * \n * return (\n * <div>\n * {isOrgAdmin && <AdminPanel />}\n * {canManageMembers && <MemberManagement />}\n * <p>Your role: {userRole}</p>\n * </div>\n * );\n * }\n * \n * // For specific organisation\n * function MultiOrgComponent() {\n * const permissions = useOrganisationPermissions('org-123');\n * \n * if (!permissions.hasOrganisationAccess) {\n * return <div>No access to this organisation</div>;\n * }\n * \n * return <div>Role in org-123: {permissions.userRole}</div>;\n * }\n * ```\n *\n * @security\n * - Validates user membership in organisation\n * - Provides role-based permission checks\n * - Ensures secure access to organisation data\n * - Real-time permission validation\n */\n\nimport { useMemo } from 'react';\nimport { useOrganisations } from '../providers/OrganisationProvider';\nimport { useOrganisationSecurity } from './useOrganisationSecurity';\nimport type { OrganisationRole, OrganisationPermission } from '../types/organisation';\n\nexport interface UseOrganisationPermissionsReturn {\n /** User's role in the organisation */\n userRole: OrganisationRole | 'no_access';\n \n /** Whether user has organisation admin role */\n isOrgAdmin: boolean;\n \n /** Whether user is a super admin */\n isSuperAdmin: boolean;\n \n /** Whether user can moderate content */\n canModerate: boolean;\n \n /** Whether user can manage members */\n canManageMembers: boolean;\n \n /** Whether user can manage organisation settings */\n canManageSettings: boolean;\n \n /** Whether user can manage events */\n canManageEvents: boolean;\n \n /** Whether user has any admin privileges */\n hasAdminPrivileges: boolean;\n \n /** Whether user has access to the organisation */\n hasOrganisationAccess: boolean;\n \n /** Check if user has specific permission */\n hasPermission: (permission: OrganisationPermission) => boolean;\n \n /** Get all permissions for the user */\n getAllPermissions: () => OrganisationPermission[];\n \n /** Organisation ID being checked */\n organisationId: string;\n}\n\n/**\n * Hook to access organisation-specific permissions and roles\n * \n * @param orgId - Optional organisation ID. Defaults to currently selected organisation\n * @returns Organisation permissions and role information\n */\nexport function useOrganisationPermissions(orgId?: string): UseOrganisationPermissionsReturn {\n const { \n selectedOrganisation, \n getUserRole, \n validateOrganisationAccess,\n ensureOrganisationContext\n } = useOrganisations();\n \n // Get super admin context if available (may not be available in all contexts)\n let superAdminContext: { isSuperAdmin: boolean } = { isSuperAdmin: false };\n try {\n superAdminContext = useOrganisationSecurity().superAdminContext;\n } catch {\n // Not available in this context, default to false\n }\n\n const organisationId = useMemo(() => {\n if (orgId) {\n return orgId;\n }\n try {\n const currentOrg = ensureOrganisationContext();\n return currentOrg.id;\n } catch {\n return '';\n }\n }, [orgId, ensureOrganisationContext]);\n\n const userRole = useMemo(() => {\n if (!organisationId) return 'no_access';\n const role = getUserRole(organisationId);\n // Map to valid OrganisationRole or 'no_access'\n if (role === 'org_admin' || role === 'leader' || role === 'member' || role === 'supporter') {\n return role as OrganisationRole;\n }\n return 'no_access';\n }, [organisationId, getUserRole]);\n\n const hasOrganisationAccess = useMemo(() => {\n if (!organisationId) return false;\n return validateOrganisationAccess(organisationId);\n }, [organisationId, validateOrganisationAccess]);\n\n const permissions = useMemo(() => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return {\n isOrgAdmin: false,\n isSuperAdmin: false,\n canModerate: false,\n canManageMembers: false,\n canManageSettings: false,\n canManageEvents: false,\n hasAdminPrivileges: false\n };\n }\n\n const isOrgAdmin = userRole === 'org_admin';\n const isLeader = userRole === 'leader';\n const isMember = userRole === 'member';\n const isSupporter = userRole === 'supporter';\n\n // Super admin status - database backed (user_metadata can be spoofed)\n // Get super admin status from the security hook\n const isSuperAdmin = superAdminContext.isSuperAdmin;\n\n return {\n isOrgAdmin,\n isSuperAdmin,\n canModerate: isSuperAdmin || isOrgAdmin || isLeader,\n canManageMembers: isSuperAdmin || isOrgAdmin || isLeader, // Leaders can manage members\n canManageSettings: isSuperAdmin || isOrgAdmin,\n canManageEvents: isSuperAdmin || isOrgAdmin || isLeader,\n hasAdminPrivileges: isSuperAdmin || isOrgAdmin || isLeader // Leaders have admin privileges\n };\n }, [hasOrganisationAccess, userRole]);\n\n const hasPermission = useMemo(() => {\n return (permission: OrganisationPermission): boolean => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return false;\n }\n\n // Super admin has all permissions (org_admin acts as super admin within org)\n if (userRole === 'org_admin' || permission === '*') {\n return true;\n }\n\n // Map permissions to roles using the defined permissions from organisation types\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n const userPermissions = rolePermissions[userRole as OrganisationRole] || [];\n return userPermissions.includes(permission) || userPermissions.includes('*');\n };\n }, [hasOrganisationAccess, userRole]);\n\n const getAllPermissions = useMemo(() => {\n return (): OrganisationPermission[] => {\n if (!hasOrganisationAccess || userRole === 'no_access') {\n return [];\n }\n\n const rolePermissions: Record<OrganisationRole, OrganisationPermission[]> = {\n supporter: ['view_basic'],\n member: ['view_basic', 'view_details'],\n leader: ['view_basic', 'view_details', 'moderate_content', 'manage_events'],\n org_admin: ['view_basic', 'view_details', 'moderate_content', 'manage_events', 'manage_members', 'manage_settings']\n };\n\n return rolePermissions[userRole as OrganisationRole] || [];\n };\n }, [hasOrganisationAccess, userRole]);\n\n return useMemo(() => ({\n userRole,\n organisationId,\n hasOrganisationAccess,\n hasPermission,\n getAllPermissions,\n ...permissions\n }), [userRole, organisationId, hasOrganisationAccess, hasPermission, getAllPermissions, permissions]);\n} ","/**\n * @file Public Event Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for accessing public event data without authentication.\n * Provides event information by event_code for public pages.\n *\n * Features:\n * - No authentication required\n * - Caching for performance\n * - Error handling and loading states\n * - TypeScript support\n * - Automatic refetch capabilities\n *\n * @example\n * ```tsx\n * import { usePublicEvent } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode } = usePublicRouteParams();\n * const { event, isLoading, error, refetch } = usePublicEvent(eventCode);\n *\n * if (isLoading) return <div>Loading event...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Date: {event.event_date}</p>\n * <p>Venue: {event.event_venue}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible public event display\n * - Supports screen reader friendly loading states\n *\n * @security\n * - Only returns public-safe event data\n * - Validates event_code before querying\n * - No sensitive information exposed\n * - Rate limiting applied at database level\n *\n * @performance\n * - Built-in caching with TTL\n * - Minimal re-renders with stable references\n * - Lazy loading support\n * - Error boundary integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - @supabase/supabase-js - Database integration\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { createClient } from '@supabase/supabase-js';\nimport type { Event } from '../../types/unified';\nimport type { Database } from '../../types/database';\nimport { usePublicPageContext } from '../../components/PublicLayout/PublicPageProvider';\nimport { logger } from '../../utils/core/logger';\n\n// Simple in-memory cache for public data\nconst publicDataCache = new Map<string, { data: any; timestamp: number; ttl: number }>();\n\nexport interface UsePublicEventReturn {\n /** The event data, null if not loaded or not found */\n event: Event | null;\n /** Whether the data is currently loading */\n isLoading: boolean;\n /** Any error that occurred during loading */\n error: Error | null;\n /** Function to manually refetch the data */\n refetch: () => Promise<void>;\n}\n\nexport interface UsePublicEventOptions {\n /** Cache TTL in milliseconds (default: 5 minutes) */\n cacheTtl?: number;\n /** Whether to enable caching (default: true) */\n enableCache?: boolean;\n}\n\n/**\n * Hook for accessing public event data by event_code\n * \n * This hook provides access to public event information without requiring\n * authentication. It includes caching, error handling, and loading states.\n * \n * @param eventCode - The event code to look up\n * @param options - Configuration options for caching and behavior\n * @returns Object containing event data, loading state, error, and refetch function\n */\nexport function usePublicEvent(\n eventCode: string,\n options: UsePublicEventOptions = {}\n): UsePublicEventReturn {\n const {\n cacheTtl = 5 * 60 * 1000, // 5 minutes\n enableCache = true\n } = options;\n\n const [event, setEvent] = useState<Event | null>(null);\n const [isLoading, setIsLoading] = useState<boolean>(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Get environment variables from public page context or fallback to direct access\n let environment: { supabaseUrl: string | null; supabaseKey: string | null };\n \n try {\n environment = usePublicPageContext().environment;\n } catch {\n // Fallback to direct environment variable access if not in PublicPageProvider\n environment = {\n supabaseUrl: (import.meta as any).env?.VITE_SUPABASE_URL || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_URL || null,\n supabaseKey: (import.meta as any).env?.VITE_SUPABASE_ANON_KEY || (import.meta as any).env?.NEXT_PUBLIC_SUPABASE_ANON_KEY || null\n };\n }\n \n // Create a simple Supabase client for public access\n const supabase = useMemo(() => {\n if (typeof window === 'undefined') return null;\n \n if (!environment.supabaseUrl || !environment.supabaseKey) {\n logger.warn('usePublicEvent', 'Missing Supabase environment variables. Please ensure VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY are set in your environment. Use publishable key if anon key is disabled.');\n return null;\n }\n\n return createClient<Database>(environment.supabaseUrl, environment.supabaseKey);\n }, [environment.supabaseUrl, environment.supabaseKey]);\n\n // Helper function to try refreshing schema cache\n const refreshSchemaCache = useCallback(async () => {\n try {\n // Try to trigger a schema refresh by querying a system table\n await (supabase as any).from('information_schema.routines').select('routine_name').limit(1);\n } catch (error) {\n // Ignore errors, this is just an attempt to refresh cache\n logger.debug('usePublicEvent', 'Schema cache refresh attempt failed:', error);\n }\n }, [supabase]);\n\n const fetchEvent = useCallback(async (): Promise<void> => {\n if (!eventCode || !supabase) {\n setError(new Error('Invalid event code or Supabase client not available'));\n setIsLoading(false);\n return;\n }\n\n // Check cache first\n const cacheKey = `public_event_${eventCode}`;\n if (enableCache) {\n const cached = publicDataCache.get(cacheKey);\n if (cached && Date.now() - cached.timestamp < cached.ttl) {\n setEvent(cached.data);\n setIsLoading(false);\n setError(null);\n return;\n }\n }\n\n try {\n setIsLoading(true);\n setError(null);\n\n let eventData: any = null;\n\n try {\n // Try to call the public event RPC function first\n const response = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n \n const data = response?.data;\n const rpcError = response?.error;\n\n if (rpcError) {\n // If RPC function doesn't exist or schema cache issue, try refresh first, then fallback\n if (rpcError.message?.includes('Could not find the function') || \n rpcError.message?.includes('does not exist') ||\n rpcError.message?.includes('schema cache')) {\n logger.warn('usePublicEvent', 'RPC function not found or schema cache issue, attempting refresh:', rpcError.message);\n \n // Try to refresh schema cache first\n await refreshSchemaCache();\n \n // Try RPC call one more time after refresh\n try {\n const retryResponse = await (supabase as any).rpc('get_public_event_by_code', {\n event_code_param: eventCode\n });\n \n const retryData = retryResponse?.data;\n const retryError = retryResponse?.error;\n \n if (!retryError && retryData && retryData.length > 0) {\n eventData = retryData[0];\n } else {\n throw new Error('RPC still failing after cache refresh');\n }\n } catch (retryError) {\n logger.warn('usePublicEvent', 'RPC still failing after cache refresh, falling back to direct table access');\n \n // Fallback: Direct table access with public RLS policy\n const tableResponse2 = await (supabase as any)\n .from('event')\n .select(`\n event_id,\n event_name,\n event_date,\n event_venue,\n event_participants,\n event_colours,\n organisation_id,\n event_days,\n event_typicalunit,\n event_rounddown,\n event_youthmultiplier,\n event_catering_email,\n event_news,\n event_billing,\n event_email\n `)\n .eq('event_code', eventCode)\n .eq('is_visible', true)\n .not('organisation_id', 'is', null)\n .limit(1)\n .single();\n\n const tableData = tableResponse2?.data;\n const tableError = tableResponse2?.error;\n\n if (tableError) {\n throw new Error(tableError?.message || 'Failed to fetch event from table');\n }\n\n if (!tableData) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n // Get event logo from file_references\n const logoResponse = await (supabase as any)\n .from('file_references')\n .select('file_path')\n .eq('table_name', 'event')\n .eq('record_id', tableData.event_id)\n .eq('is_public', true)\n .eq('file_metadata->>category', 'event_logos')\n .limit(1)\n .single();\n \n const logoData = logoResponse?.data;\n\n eventData = {\n ...tableData,\n event_logo: logoData?.file_path || null\n };\n }\n } else {\n // For RPC errors that aren't schema cache issues, throw immediately without fallback\n const errorMessage = rpcError?.message || rpcError?.toString() || 'Failed to fetch event';\n setEvent(null);\n setError(new Error(errorMessage));\n setIsLoading(false);\n return;\n }\n } else {\n if (!data || data.length === 0 || !data[0]) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n eventData = data[0];\n }\n } catch (rpcError) {\n // If RPC call fails for any reason (including schema cache issues), try direct table access\n logger.warn('usePublicEvent', 'RPC call failed, falling back to direct table access:', rpcError);\n \n const tableResponse = await (supabase as any)\n .from('event')\n .select(`\n event_id,\n event_name,\n event_date,\n event_venue,\n event_participants,\n event_colours,\n organisation_id,\n event_days,\n event_typicalunit,\n event_rounddown,\n event_youthmultiplier,\n event_catering_email,\n event_news,\n event_billing,\n event_email\n `)\n .eq('event_code', eventCode)\n .eq('is_visible', true)\n .not('organisation_id', 'is', null)\n .limit(1)\n .single();\n\n const tableData = tableResponse?.data;\n const tableError = tableResponse?.error;\n\n if (tableError) {\n throw new Error(tableError?.message || 'Failed to fetch event from table');\n }\n\n if (!tableData) {\n setEvent(null);\n setError(new Error('Event not found'));\n return;\n }\n\n // Get event logo from file_references\n const logoResponse = await (supabase as any)\n .from('file_references')\n .select('file_path')\n .eq('table_name', 'event')\n .eq('record_id', tableData.event_id)\n .eq('is_public', true)\n .eq('file_metadata->>category', 'event_logos')\n .limit(1)\n .single();\n \n const logoData = logoResponse?.data;\n\n eventData = {\n ...tableData,\n event_logo: logoData?.file_path || null\n };\n }\n \n // Transform to Event type\n const transformedEvent: Event = {\n id: eventData.event_id,\n event_id: eventData.event_id,\n event_name: eventData.event_name,\n event_code: eventCode,\n event_date: eventData.event_date,\n event_venue: eventData.event_venue,\n event_participants: eventData.event_participants,\n event_logo: eventData.event_logo,\n event_colours: eventData.event_colours,\n organisation_id: eventData.organisation_id,\n is_visible: true,\n created_at: new Date().toISOString(),\n updated_at: new Date().toISOString(),\n // Legacy compatibility\n name: eventData.event_name,\n start_date: eventData.event_date\n };\n\n setEvent(transformedEvent);\n\n // Cache the result\n if (enableCache) {\n publicDataCache.set(cacheKey, {\n data: transformedEvent,\n timestamp: Date.now(),\n ttl: cacheTtl\n });\n }\n\n } catch (err) {\n logger.error('usePublicEvent', 'Error fetching event:', err);\n const error = err instanceof Error ? err : new Error('Unknown error occurred');\n setError(error);\n setEvent(null);\n } finally {\n setIsLoading(false);\n }\n }, [eventCode, supabase, cacheTtl, enableCache]);\n\n // Fetch event when eventCode changes\n useEffect(() => {\n fetchEvent();\n }, [fetchEvent]);\n\n const refetch = useCallback(async (): Promise<void> => {\n // Clear cache for this event\n if (enableCache) {\n const cacheKey = `public_event_${eventCode}`;\n publicDataCache.delete(cacheKey);\n }\n await fetchEvent();\n }, [fetchEvent, eventCode, enableCache]);\n\n return {\n event,\n isLoading,\n error,\n refetch\n };\n}\n\n/**\n * Clear all cached public event data\n * Useful for testing or when you need to force refresh all data\n */\nexport function clearPublicEventCache(): void {\n for (const [key] of publicDataCache) {\n if (key.startsWith('public_event_')) {\n publicDataCache.delete(key);\n }\n }\n}\n\n/**\n * Get cache statistics for debugging\n */\nexport function getPublicEventCacheStats(): { size: number; keys: string[] } {\n const keys = Array.from(publicDataCache.keys()).filter(key => key.startsWith('public_event_'));\n return {\n size: keys.length,\n keys\n };\n}\n","/**\n * @file Public Route Params Hook\n * @package @jmruthers/pace-core\n * @module Hooks/Public\n * @since 1.0.0\n *\n * A React hook for extracting and validating public route parameters.\n * Provides event code extraction and validation for public pages.\n *\n * Features:\n * - URL parameter extraction\n * - Event code validation\n * - TypeScript support\n * - Error handling\n * - Route pattern support\n *\n * @example\n * ```tsx\n * import { usePublicRouteParams } from '@jmruthers/pace-core';\n *\n * function PublicEventPage() {\n * const { eventCode, eventId, event, error, isLoading } = usePublicRouteParams();\n *\n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * if (!event) return <div>Event not found</div>;\n *\n * return (\n * <div>\n * <h1>{event.event_name}</h1>\n * <p>Event Code: {eventCode}</p>\n * </div>\n * );\n * }\n * ```\n *\n * @accessibility\n * - No direct accessibility concerns (hook)\n * - Enables accessible route parameter handling\n * - Supports screen reader friendly error states\n *\n * @security\n * - Validates event codes before processing\n * - Sanitizes URL parameters\n * - No sensitive information exposed\n * - Rate limiting applied at route level\n *\n * @performance\n * - Minimal re-renders with stable references\n * - Efficient parameter extraction\n * - Caching integration\n *\n * @dependencies\n * - React 18+ - Hooks and effects\n * - React Router - URL parameter extraction\n * - Event types - Type definitions\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useParams, useLocation } from 'react-router-dom';\nimport type { Event } from '../../types/unified';\nimport { usePublicEvent } from './usePublicEvent';\n\nexport interface UsePublicRouteParamsReturn {\n /** The event code from the URL */\n eventCode: string | null;\n /** The event ID (resolved from event code) */\n eventId: string | null;\n /** The full event object */\n event: Event | null;\n /** Whether the route parameters are being processed */\n isLoading: boolean;\n /** Any error that occurred during processing */\n error: Error | null;\n /** Function to manually refetch the event data */\n refetch: () => Promise<void>;\n}\n\ninterface UsePublicRouteParamsOptions {\n /** Whether to automatically fetch event data (default: true) */\n fetchEventData?: boolean;\n /** Custom event code parameter name (default: 'eventCode') */\n eventCodeParam?: string;\n /** Whether to validate event code format (default: true) */\n validateEventCode?: boolean;\n}\n\n/**\n * Validate event code format\n * Event codes should be alphanumeric with optional hyphens/underscores in the middle\n * Supports 2-50 characters\n */\nfunction validateEventCodeFormat(eventCode: string): boolean {\n if (!eventCode || typeof eventCode !== 'string') return false;\n \n // Length check: 2-50 characters\n if (eventCode.length < 2 || eventCode.length > 50) return false;\n \n // For 2-character codes: both must be alphanumeric\n if (eventCode.length === 2) {\n return /^[a-zA-Z0-9]{2}$/.test(eventCode);\n }\n \n // For 3+ character codes: alphanumeric at start and end, hyphens/underscores allowed in middle\n // Must not start or end with hyphen/underscore\n const eventCodeRegex = /^[a-zA-Z0-9][a-zA-Z0-9_-]{1,48}[a-zA-Z0-9]$/;\n const matchesFormat = eventCodeRegex.test(eventCode);\n \n if (!matchesFormat) return false;\n \n // Additional check: no consecutive hyphens or underscores\n if (eventCode.includes('--') || eventCode.includes('__') || eventCode.includes('-_') || eventCode.includes('_-')) {\n return false;\n }\n \n return true;\n}\n\n/**\n * Hook for extracting and validating public route parameters\n * \n * This hook extracts event codes from URL parameters and optionally\n * fetches the corresponding event data. It provides validation and\n * error handling for public routes.\n * \n * @param options - Configuration options for behavior\n * @returns Object containing route parameters, event data, loading state, error, and refetch function\n */\nexport function usePublicRouteParams(\n options: UsePublicRouteParamsOptions = {}\n): UsePublicRouteParamsReturn {\n const {\n fetchEventData = true,\n eventCodeParam = 'eventCode',\n validateEventCode = true\n } = options;\n\n const params = useParams();\n const location = useLocation();\n \n const [error, setError] = useState<Error | null>(null);\n\n // Extract event code from URL parameters\n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n // Don't set error immediately - let the component handle missing eventCode gracefully\n return null;\n }\n\n // Validate event code format if requested\n if (validateEventCode && !validateEventCodeFormat(code)) {\n setError(new Error(`Invalid event code format: ${code}`));\n return null;\n }\n\n setError(null);\n return code;\n }, [params, eventCodeParam, validateEventCode]);\n\n // Use the public event hook to fetch event data\n const {\n event,\n isLoading: eventLoading,\n error: eventError,\n refetch: refetchEvent\n } = usePublicEvent(eventCode || '', {\n enableCache: true,\n cacheTtl: 5 * 60 * 1000 // 5 minutes\n });\n\n // Determine if we should show loading state\n const isLoading = useMemo(() => {\n if (!fetchEventData) return false;\n return eventLoading;\n }, [fetchEventData, eventLoading]);\n\n // Determine the final error state\n const finalError = useMemo(() => {\n if (error) return error;\n if (eventError) return eventError;\n return null;\n }, [error, eventError]);\n\n // Extract event ID from event data\n const eventId = useMemo(() => {\n if (!event) return null;\n return event.event_id || event.id;\n }, [event]);\n\n // Refetch function\n const refetch = useCallback(async (): Promise<void> => {\n if (!fetchEventData) return;\n await refetchEvent();\n }, [fetchEventData, refetchEvent]);\n\n return {\n eventCode,\n eventId,\n event: fetchEventData ? event : null,\n isLoading,\n error: finalError,\n refetch\n };\n}\n\n/**\n * Hook for extracting just the event code without fetching event data\n * Useful when you only need the event code and will fetch data separately\n */\nexport function usePublicEventCode(\n eventCodeParam: string = 'eventCode'\n): { eventCode: string | null; error: Error | null } {\n const params = useParams();\n \n const eventCode = useMemo(() => {\n const code = params[eventCodeParam] as string;\n \n if (!code) {\n return null;\n }\n\n // Validate event code format\n if (!validateEventCodeFormat(code)) {\n return null;\n }\n\n return code;\n }, [params, eventCodeParam]);\n\n const error = useMemo(() => {\n if (!eventCode) {\n return new Error(`Event code parameter '${eventCodeParam}' not found or invalid`);\n }\n return null;\n }, [eventCode, eventCodeParam]);\n\n return {\n eventCode,\n error\n };\n}\n\n/**\n * Utility function to generate public route paths\n */\nexport function generatePublicRoutePath(\n eventCode: string,\n pageName: string = 'index'\n): string {\n if (!eventCode || !validateEventCodeFormat(eventCode)) {\n throw new Error('Invalid event code for route generation');\n }\n \n return `/public/event/${eventCode}/${pageName}`;\n}\n\n/**\n * Utility function to extract event code from a public route path\n * Supports 2-50 character event codes\n */\nexport function extractEventCodeFromPath(path: string): string | null {\n const match = path.match(/^\\/public\\/event\\/([a-zA-Z0-9_-]{2,50})(?:\\/.*)?$/);\n if (!match) return null;\n \n const eventCode = match[1];\n // Validate the extracted code using the same validation function\n if (!validateEventCodeFormat(eventCode)) {\n return null;\n }\n \n return eventCode;\n}\n"],"mappings":"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","names":["useMemo","useMemo","useState","useEffect","useCallback","useMemo","useState","useMemo","useCallback","error","useEffect","useState","useCallback","useMemo","useState","useMemo","useCallback"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/rbac/hooks/useRBAC.ts","../src/rbac/hooks/useResolvedScope.ts","../src/rbac/utils/eventContext.ts","../src/rbac/hooks/usePermissions.ts","../src/rbac/hooks/useResourcePermissions.ts","../src/rbac/hooks/useRoleManagement.ts"],"sourcesContent":["/**\n * @file RBAC Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 0.3.0\n *\n * A React hook that provides access to the RBAC (Role-Based Access Control) system\n * through the hardened RBAC engine API. The hook defers all permission and role\n * resolution to the shared engine to ensure consistent security behaviour across\n * applications.\n */\n\nimport { useState, useEffect, useCallback, useMemo } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport {\n getPermissionMap,\n getAccessLevel,\n resolveAppContext,\n getRoleContext,\n} from '../api';\nimport { getRBACLogger } from '../config';\nimport type {\n UserRBACContext,\n GlobalRole,\n OrganisationRole,\n EventAppRole,\n Permission,\n Scope,\n PermissionMap,\n UUID,\n} from '../types';\n\nfunction mapAccessLevelToEventRole(level: string | null): EventAppRole | null {\n switch (level) {\n case 'viewer':\n return 'viewer';\n case 'participant':\n return 'participant';\n case 'planner':\n return 'planner';\n case 'admin':\n case 'super':\n return 'event_admin';\n default:\n return null;\n }\n}\n\nexport function useRBAC(pageId?: string): UserRBACContext {\n const logger = getRBACLogger();\n // Get all context from UnifiedAuth - it already provides selectedOrganisation, isContextReady, selectedEvent, and eventLoading\n // This is more reliable than calling useOrganisations()/useEvents() separately which might throw or return stale values\n const { \n user, \n session, \n appName, \n appConfig,\n selectedOrganisation,\n isContextReady: orgContextReady,\n organisationLoading: orgLoading,\n selectedEvent,\n eventLoading\n } = useUnifiedAuth();\n \n // Check if app requires event context\n // IMPORTANT: If appConfig is null initially, default to true (safer for event-based apps)\n // This prevents premature loading when appConfig hasn't loaded yet\n const requiresEvent = appConfig?.requires_event ?? (appConfig === null ? true : false);\n \n // Only log hook initialization if user is authenticated to avoid noise during login\n // Log hook initialization for debugging (use warn level so it's always visible)\n // Also use direct console.log as fallback to ensure visibility\n if (user && session) {\n const hookInitLog = {\n appName,\n requiresEvent,\n appConfig: appConfig ? JSON.stringify(appConfig) : 'null',\n hasUser: !!user,\n hasSession: !!session,\n hasSelectedEvent: !!selectedEvent,\n eventLoading,\n selectedEventId: selectedEvent?.event_id,\n hasSelectedOrganisation: !!selectedOrganisation,\n organisationId: selectedOrganisation?.id,\n orgContextReady,\n orgLoading\n };\n logger.warn('[useRBAC] Hook initialized', hookInitLog);\n // Direct console.log as fallback to ensure we can see if hook is called\n console.warn('[useRBAC] Hook initialized (direct log)', hookInitLog);\n }\n\n const [globalRole, setGlobalRole] = useState<GlobalRole | null>(null);\n const [organisationRole, setOrganisationRole] = useState<OrganisationRole | null>(null);\n const [eventAppRole, setEventAppRole] = useState<EventAppRole | null>(null);\n const [permissionMap, setPermissionMap] = useState<PermissionMap>({} as PermissionMap);\n const [currentScope, setCurrentScope] = useState<Scope | null>(null);\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n const resetState = useCallback(() => {\n setGlobalRole(null);\n setOrganisationRole(null);\n setEventAppRole(null);\n setPermissionMap({} as PermissionMap);\n setCurrentScope(null);\n }, []);\n\n const loadRBACContext = useCallback(async () => {\n // Early return if user is not authenticated - don't do anything\n if (!user || !session) {\n resetState();\n setIsLoading(false);\n return;\n }\n\n // Wait for organisation context to be ready before loading RBAC\n // This is critical - without organisation ID, RPC calls can't resolve permissions\n if (orgLoading || !orgContextReady || !selectedOrganisation?.id) {\n setIsLoading(true);\n logger.warn('[useRBAC] Waiting for organisation context before loading RBAC context', {\n orgLoading,\n orgContextReady,\n hasSelectedOrganisation: !!selectedOrganisation,\n organisationId: selectedOrganisation?.id,\n appName\n });\n return;\n }\n\n // For event-based apps, wait for event context to be ready before loading RBAC\n // This prevents NetworkError when RPC calls are made before event context is available\n if (requiresEvent) {\n if (eventLoading || !selectedEvent) {\n // Event context not ready yet - don't load RBAC yet\n // This prevents premature RPC calls that can cause NetworkError\n // Set loading state so React knows we're waiting\n setIsLoading(true);\n logger.warn('[useRBAC] Waiting for event context before loading RBAC context', {\n eventLoading,\n hasSelectedEvent: !!selectedEvent,\n appName,\n selectedEventId: selectedEvent?.event_id,\n organisationId: selectedOrganisation?.id\n });\n return;\n }\n }\n\n setIsLoading(true);\n setError(null);\n\n logger.warn('[useRBAC] Loading RBAC context', {\n appName,\n requiresEvent,\n hasSelectedEvent: !!selectedEvent,\n selectedEventId: selectedEvent?.event_id,\n organisationId: selectedOrganisation?.id\n });\n\n try {\n let appId: UUID | undefined;\n if (appName) {\n // Wrap RPC call in try-catch to handle NetworkError gracefully\n try {\n const resolved = await resolveAppContext({ userId: user.id as UUID, appName });\n if (!resolved || !resolved.hasAccess) {\n throw new Error(`User does not have access to app \"${appName}\"`);\n }\n appId = resolved.appId;\n } catch (rpcError: any) {\n // Handle NetworkError - might be due to timing issue\n if (rpcError?.message?.includes('NetworkError') || rpcError?.message?.includes('fetch')) {\n logger.warn('[useRBAC] NetworkError resolving app context - may be timing issue, will retry when context is ready', {\n appName,\n error: rpcError.message,\n requiresEvent,\n eventLoading,\n hasSelectedEvent: !!selectedEvent\n });\n // Don't throw - let it retry when dependencies change\n setIsLoading(false);\n return;\n }\n // Re-throw other errors\n throw rpcError;\n }\n }\n\n const scope: Scope = {\n organisationId: selectedOrganisation?.id,\n eventId: selectedEvent?.event_id || undefined,\n appId,\n };\n \n // Log scope to verify it's built correctly\n logger.warn('[useRBAC] Building scope for RBAC context', {\n organisationId: scope.organisationId,\n eventId: scope.eventId,\n appId: scope.appId,\n hasOrganisationId: !!scope.organisationId,\n hasEventId: !!scope.eventId\n });\n \n setCurrentScope(scope);\n\n const [map, roleContext, accessLevel] = await Promise.all([\n getPermissionMap({ userId: user.id as UUID, scope }),\n getRoleContext({ userId: user.id as UUID, scope }),\n getAccessLevel({ userId: user.id as UUID, scope }),\n ]);\n\n setPermissionMap(map);\n setGlobalRole(roleContext.globalRole);\n setOrganisationRole(roleContext.organisationRole);\n setEventAppRole(roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel));\n \n logger.warn('[useRBAC] RBAC context loaded successfully', {\n appName,\n permissionCount: Object.keys(map).length,\n globalRole: roleContext.globalRole,\n organisationRole: roleContext.organisationRole,\n eventAppRole: roleContext.eventAppRole || mapAccessLevelToEventRole(accessLevel)\n });\n } catch (err) {\n const handledError = err instanceof Error ? err : new Error('Failed to load RBAC context');\n logger.error('[useRBAC] Error loading RBAC context:', handledError);\n setError(handledError);\n resetState();\n } finally {\n setIsLoading(false);\n }\n }, [appName, logger, resetState, selectedEvent?.event_id, selectedOrganisation?.id, session, user, requiresEvent, eventLoading, appConfig, orgContextReady, orgLoading]);\n\n const hasGlobalPermission = useCallback(\n (permission: string): boolean => {\n if (globalRole === 'super_admin' || permissionMap['*']) {\n return true;\n }\n\n if (permission === 'super_admin') {\n return globalRole === 'super_admin';\n }\n\n if (permission === 'org_admin') {\n return organisationRole === 'org_admin';\n }\n\n return permissionMap[permission as Permission] === true;\n },\n [globalRole, organisationRole, permissionMap],\n );\n\n const isSuperAdmin = useMemo(() => globalRole === 'super_admin' || permissionMap['*'] === true, [globalRole, permissionMap]);\n const isOrgAdmin = useMemo(() => organisationRole === 'org_admin' || isSuperAdmin, [organisationRole, isSuperAdmin]);\n const isEventAdmin = useMemo(() => eventAppRole === 'event_admin' || isSuperAdmin, [eventAppRole, isSuperAdmin]);\n const canManageOrganisation = useMemo(() => isSuperAdmin || organisationRole === 'org_admin', [isSuperAdmin, organisationRole]);\n const canManageEvent = useMemo(() => isSuperAdmin || eventAppRole === 'event_admin', [isSuperAdmin, eventAppRole]);\n\n useEffect(() => {\n // Log when effect runs to help debug\n logger.warn('[useRBAC] useEffect triggered - calling loadRBACContext', {\n appName,\n requiresEvent,\n eventLoading,\n hasSelectedEvent: !!selectedEvent,\n selectedEventId: selectedEvent?.event_id,\n hasUser: !!user,\n hasSession: !!session,\n hasSelectedOrganisation: !!selectedOrganisation,\n organisationId: selectedOrganisation?.id,\n orgContextReady,\n orgLoading\n });\n loadRBACContext();\n }, [loadRBACContext, appName, requiresEvent, eventLoading, selectedEvent?.event_id, user, session, selectedOrganisation?.id, orgContextReady, orgLoading]);\n\n return {\n user,\n globalRole,\n organisationRole,\n eventAppRole,\n hasGlobalPermission,\n isSuperAdmin,\n isOrgAdmin,\n isEventAdmin,\n canManageOrganisation,\n canManageEvent,\n isLoading,\n error,\n };\n}\n","/**\n * @file useResolvedScope Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * Shared hook for resolving RBAC scope from various contexts.\n * This hook is used by both DataTable and PagePermissionGuard to ensure\n * consistent scope resolution logic.\n */\n\nimport { useEffect, useState, useRef } from 'react';\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport type { Database } from '../../types/database';\nimport type { Scope } from '../types';\nimport { createScopeFromEvent } from '../utils/eventContext';\nimport { getCurrentAppName } from '../../utils/app/appNameResolver';\nimport { createLogger } from '../../utils/core/logger';\n\nconst log = createLogger('useResolvedScope');\n\nexport interface UseResolvedScopeOptions {\n /** Supabase client instance */\n supabase: SupabaseClient<Database> | null;\n /** Selected organisation ID */\n selectedOrganisationId: string | null;\n /** Selected event ID */\n selectedEventId: string | null;\n}\n\nexport interface UseResolvedScopeReturn {\n /** Resolved scope, or null if not yet resolved */\n resolvedScope: Scope | null;\n /** Whether the scope resolution is in progress */\n isLoading: boolean;\n /** Error if scope resolution failed */\n error: Error | null;\n}\n\n/**\n * Resolves RBAC scope from organisation and event context\n * \n * This hook handles the complex logic of determining the correct RBAC scope\n * based on available context (organisation, event, app). It ensures consistent\n * scope resolution across the application.\n * \n * @param options - Hook options\n * @returns Resolved scope and loading state\n * \n * @example\n * ```tsx\n * const { resolvedScope, isLoading } = useResolvedScope({\n * supabase,\n * selectedOrganisationId,\n * selectedEventId\n * });\n * \n * if (isLoading) return <Loading />;\n * if (!resolvedScope) return <Error />;\n * \n * const permission = useCan(userId, resolvedScope, permission);\n * ```\n */\nexport function useResolvedScope({\n supabase,\n selectedOrganisationId,\n selectedEventId\n}: UseResolvedScopeOptions): UseResolvedScopeReturn {\n const [resolvedScope, setResolvedScope] = useState<Scope | null>(null);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n \n // Use a ref to track the stable scope and only update it when it actually changes\n const stableScopeRef = useRef<{ organisationId: string; appId: string; eventId: string | undefined }>({ \n organisationId: '', \n appId: '', \n eventId: undefined \n });\n \n // Update stable scope ref in useEffect to avoid updates during render\n useEffect(() => {\n if (resolvedScope && resolvedScope.organisationId) {\n const newScope = {\n organisationId: resolvedScope.organisationId,\n appId: resolvedScope.appId,\n eventId: resolvedScope.eventId\n };\n \n // Only update if the scope has actually changed\n if (stableScopeRef.current.organisationId !== newScope.organisationId ||\n stableScopeRef.current.eventId !== newScope.eventId ||\n stableScopeRef.current.appId !== newScope.appId) {\n stableScopeRef.current = {\n organisationId: newScope.organisationId,\n appId: newScope.appId || '',\n eventId: newScope.eventId\n };\n }\n } else if (!resolvedScope) {\n // Reset to empty scope when no resolved scope\n stableScopeRef.current = { organisationId: '', appId: '', eventId: undefined };\n }\n }, [resolvedScope]);\n \n const stableScope = stableScopeRef.current;\n \n useEffect(() => {\n let cancelled = false;\n \n const resolveScope = async () => {\n setIsLoading(true);\n setError(null);\n \n try {\n // Get app ID from package.json or environment\n let appId: string | undefined = undefined;\n \n // Try to resolve from database\n if (supabase) {\n const appName = getCurrentAppName();\n if (appName) {\n try {\n const { data: app, error } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .eq('is_active', true)\n .single() as { data: { id: string; name: string; is_active: boolean } | null; error: any };\n \n if (error) {\n // Check if app exists but is inactive\n const { data: inactiveApp } = await supabase\n .from('rbac_apps')\n .select('id, name, is_active')\n .eq('name', appName)\n .single() as { data: { id: string; name: string; is_active: boolean } | null };\n \n if (inactiveApp) {\n log.error(`App \"${appName}\" exists but is inactive (is_active: ${inactiveApp.is_active})`);\n } else {\n log.error(`App \"${appName}\" not found in rbac_apps table`);\n }\n } else if (app) {\n appId = app.id;\n }\n } catch (error) {\n log.error('Unexpected error resolving app ID:', error);\n }\n }\n }\n\n // Resolve scope based on available context\n\n // If we have both organisation and event, use them directly\n if (selectedOrganisationId && selectedEventId) {\n if (!cancelled) {\n setResolvedScope({\n organisationId: selectedOrganisationId,\n eventId: selectedEventId,\n appId: appId\n });\n setIsLoading(false);\n }\n return;\n }\n\n // If we only have organisation, use it\n if (selectedOrganisationId) {\n if (!cancelled) {\n setResolvedScope({\n organisationId: selectedOrganisationId,\n eventId: selectedEventId || undefined,\n appId: appId\n });\n setIsLoading(false);\n }\n return;\n }\n\n // If we only have event, resolve organisation from event\n if (selectedEventId && supabase) {\n try {\n const eventScope = await createScopeFromEvent(supabase, selectedEventId, appId);\n if (!eventScope) {\n log.error('Could not resolve organization from event context');\n if (!cancelled) {\n setResolvedScope(null);\n setError(new Error('Could not resolve organisation from event context'));\n setIsLoading(false);\n }\n return;\n }\n // Preserve the resolved app ID\n if (!cancelled) {\n setResolvedScope({\n ...eventScope,\n appId: appId || eventScope.appId\n });\n setIsLoading(false);\n }\n } catch (err) {\n log.error('Error resolving scope from event:', err);\n if (!cancelled) {\n setResolvedScope(null);\n setError(err as Error);\n setIsLoading(false);\n }\n }\n return;\n }\n\n // No context available\n log.error('No organisation or event context available');\n if (!cancelled) {\n setResolvedScope(null);\n setError(new Error('No organisation or event context available'));\n setIsLoading(false);\n }\n } catch (err) {\n if (!cancelled) {\n setError(err as Error);\n setIsLoading(false);\n }\n }\n };\n\n resolveScope();\n \n return () => {\n cancelled = true;\n };\n }, [selectedOrganisationId, selectedEventId, supabase]);\n \n return {\n resolvedScope: stableScope.organisationId ? stableScope as Scope : null,\n isLoading,\n error\n };\n}\n","/**\n * Event Context Utilities for RBAC\n * @package @jmruthers/pace-core\n * @module RBAC/EventContext\n * @since 1.0.0\n * \n * This module provides utilities for event-based RBAC operations where\n * the organization context is derived from the event context.\n */\n\nimport { SupabaseClient } from '@supabase/supabase-js';\nimport { Database } from '../../types/database';\nimport { UUID, Scope } from '../types';\n\n/**\n * Get organization ID from event ID\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @returns Promise resolving to organization ID or null\n */\nexport async function getOrganisationFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string\n): Promise<UUID | null> {\n const { data, error } = await supabase\n .from('event')\n .select('organisation_id')\n .eq('event_id', eventId)\n .single() as { data: { organisation_id: string } | null; error: any };\n\n if (error || !data) {\n return null;\n }\n\n return data.organisation_id;\n}\n\n/**\n * Create a complete scope from event context\n * \n * @param supabase - Supabase client\n * @param eventId - Event ID\n * @param appId - Optional app ID\n * @returns Promise resolving to complete scope\n */\nexport async function createScopeFromEvent(\n supabase: SupabaseClient<Database>,\n eventId: string,\n appId?: UUID\n): Promise<Scope | null> {\n const organisationId = await getOrganisationFromEvent(supabase, eventId);\n \n if (!organisationId) {\n return null;\n }\n\n return {\n organisationId,\n eventId,\n appId\n };\n}\n\n/**\n * Check if a scope is event-based (has eventId but no explicit organisationId)\n * \n * @param scope - Permission scope\n * @returns True if scope is event-based\n */\nexport function isEventBasedScope(scope: Scope): boolean {\n return !scope.organisationId && !!scope.eventId;\n}\n\n/**\n * Validate that an event-based scope has the required context\n * \n * @param scope - Permission scope\n * @returns True if scope is valid for event-based operations\n */\nexport function isValidEventBasedScope(scope: Scope): boolean {\n return isEventBasedScope(scope) && !!scope.eventId;\n}\n","/**\n * @file RBAC Permission Hooks\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * This module provides React hooks for RBAC functionality.\n */\n\nimport React, { useState, useEffect, useCallback, useMemo, useRef } from 'react';\nimport { \n UUID, \n Scope, \n Permission, \n PermissionMap\n} from '../types';\nimport { AccessLevel as AccessLevelType } from '../types';\nimport { \n getAccessLevel, \n getPermissionMap, \n isPermitted,\n isPermittedCached \n} from '../api';\nimport { getRBACLogger } from '../config';\n\n/**\n * Hook to get user's permissions in a scope\n * \n * @param userId - User ID\n * @param organisationId - Organisation ID\n * @param eventId - Event ID (optional)\n * @param appId - Application ID (optional)\n * @returns Permission state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { permissions, isLoading, error } = usePermissions(\n * userId, \n * organisationId, \n * eventId, \n * appId\n * );\n * \n * if (isLoading) return <div>Loading...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {permissions['read:users'] && <UserList />}\n * {permissions['create:users'] && <CreateUserButton />}\n * </div>\n * );\n * }\n * ```\n */\nexport function usePermissions(\n userId: UUID, \n organisationId: string | undefined, \n eventId: string | undefined, \n appId: string | undefined\n) {\n const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n const [fetchTrigger, setFetchTrigger] = useState(0);\n const isFetchingRef = useRef(false);\n const logger = getRBACLogger();\n \n // Track previous values to detect changes imperatively\n const prevValuesRef = useRef({ userId, organisationId, eventId, appId });\n \n // Normalize organisationId to empty string if undefined\n const orgId = organisationId || '';\n \n // Log when hook is called with new scope (every render)\n // This helps us see if React is calling the hook with updated scope\n logger.warn('[usePermissions] Hook called with scope', {\n userId,\n organisationId: orgId,\n eventId,\n appId,\n hasAppId: !!appId,\n hasOrganisationId: !!orgId\n });\n \n // Log when scope changes to verify React detects the change\n React.useEffect(() => {\n logger.warn('[usePermissions] Scope changed (useEffect)', {\n userId,\n organisationId,\n eventId,\n appId,\n hasAppId: !!appId,\n hasOrganisationId: !!organisationId\n });\n }, [userId, organisationId, eventId, appId]);\n\n // Add timeout for missing organisation context (3 seconds)\n useEffect(() => {\n if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {\n const timeoutId = setTimeout(() => {\n setError(new Error('Organisation context is required for permission checks'));\n setIsLoading(false);\n }, 3000); // 3 seconds - typical permission check is < 1 second\n \n return () => clearTimeout(timeoutId);\n }\n // Clear error if organisation context becomes available\n if (error?.message === 'Organisation context is required for permission checks') {\n setError(null);\n }\n }, [organisationId, error]);\n\n // CRITICAL: Detect parameter changes imperatively and trigger fetch\n // This bypasses React's useEffect dependency tracking which is failing to detect appId changes\n const paramsChanged = \n prevValuesRef.current.userId !== userId ||\n prevValuesRef.current.organisationId !== organisationId ||\n prevValuesRef.current.eventId !== eventId ||\n prevValuesRef.current.appId !== appId;\n \n if (paramsChanged) {\n logger.warn('[usePermissions] Parameters changed - triggering fetch', {\n userId,\n organisationId: orgId,\n eventId,\n appId,\n hasAppId: !!appId,\n prevAppId: prevValuesRef.current.appId,\n appIdChanged: prevValuesRef.current.appId !== appId\n });\n prevValuesRef.current = { userId, organisationId, eventId, appId };\n // Increment counter to force useEffect to run\n setFetchTrigger(prev => prev + 1);\n }\n\n useEffect(() => {\n const fetchPermissions = async () => {\n logger.warn('[usePermissions] Fetch useEffect triggered', {\n userId,\n orgId,\n eventId,\n appId,\n hasAppId: !!appId,\n isFetching: isFetchingRef.current\n });\n\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n logger.warn('[usePermissions] Skipping fetch - already fetching', {\n userId,\n scope: {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n }\n });\n return;\n }\n\n if (!userId) {\n logger.warn('[usePermissions] Skipping fetch - no userId');\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n // Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)\n // Wait for organisation context to resolve\n // IMPORTANT: Don't clear existing permissions here - keep them until we have new ones\n if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {\n logger.warn('[usePermissions] Skipping fetch - no orgId', {\n orgId,\n hasOrgId: !!orgId\n });\n // Keep existing permissions, just mark as loading\n setIsLoading(true);\n setError(null);\n return;\n }\n\n // Note: getPermissionMap can work without appId, but will return limited permissions\n // In test environments, appId might be undefined, so we still attempt the fetch\n // If appId is missing in production, it will return an empty map which is acceptable\n if (!appId) {\n logger.warn('[usePermissions] Fetching permissions without appId (may return limited permissions)', {\n userId,\n organisationId: orgId,\n eventId: eventId,\n hasAppId: false\n });\n // Continue with fetch - don't block on appId\n }\n logger.warn('[usePermissions] Fetching permissions', {\n userId,\n scope: {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n },\n hasAppId: !!appId\n });\n\n try {\n isFetchingRef.current = true;\n setIsLoading(true);\n setError(null);\n \n // Build scope object for API call\n const scope: Scope = {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n };\n \n // Fetch new permissions - don't clear old ones until we have new ones\n const permissionMap = await getPermissionMap({ userId, scope });\n \n logger.warn('[usePermissions] Permissions fetched successfully', {\n permissionCount: Object.keys(permissionMap).length,\n hasWildcard: !!permissionMap['*'],\n scope: {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n }\n });\n \n // Only update permissions if fetch was successful\n setPermissions(permissionMap);\n } catch (err) {\n // On error, keep existing permissions but set error state\n // This prevents the UI from losing all items when there's a transient error\n logger.error('[usePermissions] Failed to fetch permissions:', err);\n setError(err instanceof Error ? err : new Error('Failed to fetch permissions'));\n // Don't clear permissions on error - keep what we had\n } finally {\n setIsLoading(false);\n isFetchingRef.current = false;\n }\n };\n\n fetchPermissions();\n }, [fetchTrigger, userId, organisationId, eventId, appId]);\n\n const hasPermission = useCallback((permission: Permission): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissions[permission] === true;\n }, [permissions]);\n\n const hasAnyPermission = useCallback((permissionList: Permission[]): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissionList.some(p => permissions[p] === true);\n }, [permissions]);\n\n const hasAllPermissions = useCallback((permissionList: Permission[]): boolean => {\n if (permissions['*']) {\n return true;\n }\n return permissionList.every(p => permissions[p] === true);\n }, [permissions]);\n\n const refetch = useCallback(async () => {\n // Prevent multiple simultaneous fetches\n if (isFetchingRef.current) {\n return;\n }\n\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n // Don't fetch permissions if scope is invalid (e.g., organisationId is null/empty)\n // IMPORTANT: Don't clear existing permissions - keep them until we have new ones\n if (!orgId || orgId === null || (typeof orgId === 'string' && orgId.trim() === '')) {\n // Keep existing permissions, just mark as loading\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n isFetchingRef.current = true;\n setIsLoading(true);\n setError(null);\n \n // Build scope object for API call\n const scope: Scope = {\n organisationId: orgId,\n eventId: eventId,\n appId: appId\n };\n \n // Fetch new permissions - don't clear old ones until we have new ones\n const permissionMap = await getPermissionMap({ userId, scope });\n \n // Only update permissions if fetch was successful\n setPermissions(permissionMap);\n } catch (err) {\n // On error, keep existing permissions but set error state\n // This prevents the UI from losing all items when there's a transient error\n const logger = getRBACLogger();\n logger.error('Failed to refetch permissions:', err);\n setError(err instanceof Error ? err : new Error('Failed to fetch permissions'));\n // Don't clear permissions on error - keep what we had\n } finally {\n setIsLoading(false);\n isFetchingRef.current = false;\n }\n }, [userId, organisationId, eventId, appId]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n permissions,\n isLoading,\n error,\n hasPermission,\n hasAnyPermission,\n hasAllPermissions,\n refetch\n }), [permissions, isLoading, error, hasPermission, hasAnyPermission, hasAllPermissions, refetch]);\n}\n\n/**\n * Hook to check if user can perform an action\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permission - Permission to check\n * @param pageId - Optional page ID\n * @param useCache - Whether to use cached results\n * @returns Permission check state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { can, isLoading, error } = useCan(userId, scope, 'read:users');\n * \n * if (isLoading) return <div>Checking permission...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return can ? <UserList /> : <div>Access denied</div>;\n * }\n * ```\n */\nexport function useCan(\n userId: UUID, \n scope: Scope, \n permission: Permission, \n pageId?: UUID,\n useCache: boolean = true\n) {\n const [can, setCan] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n // Validate scope parameter - handle undefined/null scope gracefully\n const isValidScope = scope && typeof scope === 'object';\n const organisationId = isValidScope ? scope.organisationId : undefined;\n const eventId = isValidScope ? scope.eventId : undefined;\n const appId = isValidScope ? scope.appId : undefined;\n\n // Add timeout for missing organisation context (3 seconds)\n useEffect(() => {\n if (!isValidScope || !organisationId || organisationId === null || (typeof organisationId === 'string' && organisationId.trim() === '')) {\n const timeoutId = setTimeout(() => {\n setError(new Error('Organisation context is required for permission checks'));\n setIsLoading(false);\n setCan(false);\n }, 3000); // 3 seconds - typical permission check is < 1 second\n \n return () => clearTimeout(timeoutId);\n }\n // Clear error if organisation context becomes available\n if (error?.message === 'Organisation context is required for permission checks') {\n setError(null);\n }\n }, [isValidScope, organisationId, error]);\n\n // Use refs to track the last values to prevent unnecessary re-runs\n const lastUserIdRef = useRef<UUID | null>(null);\n const lastScopeRef = useRef<string | null>(null);\n const lastPermissionRef = useRef<Permission | null>(null);\n const lastPageIdRef = useRef<UUID | undefined | null>(null);\n const lastUseCacheRef = useRef<boolean | null>(null);\n\n useEffect(() => {\n // Create a scope key to track changes - use safe property access\n const scopeKey = isValidScope ? `${organisationId}-${eventId}-${appId}` : 'invalid-scope';\n \n // Only run if something has actually changed\n if (\n lastUserIdRef.current !== userId ||\n lastScopeRef.current !== scopeKey ||\n lastPermissionRef.current !== permission ||\n lastPageIdRef.current !== pageId ||\n lastUseCacheRef.current !== useCache\n ) {\n lastUserIdRef.current = userId;\n lastScopeRef.current = scopeKey;\n lastPermissionRef.current = permission;\n lastPageIdRef.current = pageId;\n lastUseCacheRef.current = useCache;\n \n // Inline the permission check logic to avoid useCallback dependency issues\n const checkPermission = async () => {\n if (!userId) {\n setCan(false);\n setIsLoading(false);\n return;\n }\n\n // Validate scope before accessing properties\n if (!isValidScope) {\n setIsLoading(true);\n setCan(false);\n setError(null);\n // Timeout is handled in separate useEffect\n return;\n }\n\n // Don't check permissions if scope is invalid (e.g., organisationId is null/empty)\n // Wait for organisation context to resolve\n if (!organisationId || organisationId === null || (typeof organisationId === 'string' && organisationId.trim() === '')) {\n setIsLoading(true);\n setCan(false);\n setError(null);\n // Timeout is handled in separate useEffect (Phase 1.4)\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n // Create a valid scope object for the API call\n const validScope: Scope = {\n organisationId,\n ...(eventId ? { eventId } : {}),\n ...(appId ? { appId } : {})\n };\n \n const result = useCache \n ? await isPermittedCached({ userId, scope: validScope, permission, pageId })\n : await isPermitted({ userId, scope: validScope, permission, pageId });\n \n setCan(result);\n } catch (err) {\n const logger = getRBACLogger();\n logger.error('Permission check error:', { permission, error: err });\n setError(err instanceof Error ? err : new Error('Failed to check permission'));\n setCan(false);\n } finally {\n setIsLoading(false);\n }\n };\n \n checkPermission();\n }\n }, [userId, isValidScope, organisationId, eventId, appId, permission, pageId, useCache]);\n\n const refetch = useCallback(async () => {\n if (!userId) {\n setCan(false);\n setIsLoading(false);\n return;\n }\n\n // Validate scope before accessing properties\n if (!isValidScope) {\n setCan(false);\n setIsLoading(true);\n setError(null);\n return;\n }\n\n // Don't check permissions if scope is invalid (e.g., organisationId is null/empty)\n if (!organisationId || organisationId === null || (typeof organisationId === 'string' && organisationId.trim() === '')) {\n setCan(false);\n setIsLoading(true);\n setError(null);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n // Create a valid scope object for the API call\n const validScope: Scope = {\n organisationId,\n ...(eventId ? { eventId } : {}),\n ...(appId ? { appId } : {})\n };\n \n const result = useCache \n ? await isPermittedCached({ userId, scope: validScope, permission, pageId })\n : await isPermitted({ userId, scope: validScope, permission, pageId });\n \n setCan(result);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permission'));\n setCan(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, isValidScope, organisationId, eventId, appId, permission, pageId, useCache]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n can,\n isLoading,\n error,\n refetch\n }), [can, isLoading, error, refetch]);\n}\n\n/**\n * Hook to get user's access level in a scope\n * \n * @param userId - User ID\n * @param scope - Scope for access level checking\n * @returns Access level state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { accessLevel, isLoading, error } = useAccessLevel(userId, scope);\n * \n * if (isLoading) return <div>Loading access level...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * Access Level: {accessLevel}\n * {accessLevel >= AccessLevel.ADMIN && <AdminPanel />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useAccessLevel(userId: UUID, scope: Scope): {\n accessLevel: AccessLevelType;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [accessLevel, setAccessLevel] = useState<AccessLevelType>('viewer');\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchAccessLevel = useCallback(async () => {\n if (!userId) {\n setAccessLevel('viewer');\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const level = await getAccessLevel({ userId, scope });\n setAccessLevel(level);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to fetch access level'));\n setAccessLevel('viewer');\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n useEffect(() => {\n fetchAccessLevel();\n }, [fetchAccessLevel]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n accessLevel,\n isLoading,\n error,\n refetch: fetchAccessLevel\n }), [accessLevel, isLoading, error, fetchAccessLevel]);\n}\n\n/**\n * Hook to check multiple permissions at once\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Multiple permission check results\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { results, isLoading, error } = useMultiplePermissions(\n * userId, \n * scope, \n * ['read:users', 'create:users', 'update:users']\n * );\n * \n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {results['read:users'] && <UserList />}\n * {results['create:users'] && <CreateUserButton />}\n * {results['update:users'] && <EditUserButton />}\n * </div>\n * );\n * }\n * ```\n */\nexport function useMultiplePermissions(\n userId: UUID, \n scope: Scope, \n permissions: Permission[],\n useCache: boolean = true\n): {\n results: Record<Permission, boolean>;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [results, setResults] = useState<Record<Permission, boolean>>({} as Record<Permission, boolean>);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkPermissions = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setResults({} as Record<Permission, boolean>);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const permissionResults: Record<Permission, boolean> = {} as Record<Permission, boolean>;\n \n // Check each permission\n for (const permission of permissions) {\n const result = useCache \n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n permissionResults[permission] = result;\n }\n \n setResults(permissionResults);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setResults({} as Record<Permission, boolean>);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkPermissions();\n }, [checkPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n results,\n isLoading,\n error,\n refetch: checkPermissions\n }), [results, isLoading, error, checkPermissions]);\n}\n\n/**\n * Hook to check if user has any of the specified permissions\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Whether user has any of the permissions\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { hasAny, isLoading, error } = useHasAnyPermission(\n * userId, \n * scope, \n * ['read:users', 'create:users']\n * );\n * \n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return hasAny ? <UserManagementPanel /> : <div>No user permissions</div>;\n * }\n * ```\n */\nexport function useHasAnyPermission(\n userId: UUID, \n scope: Scope, \n permissions: Permission[],\n useCache: boolean = true\n): {\n hasAny: boolean;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [hasAny, setHasAny] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkAnyPermission = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setHasAny(false);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n let hasAnyPermission = false;\n \n for (const permission of permissions) {\n const result = useCache \n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n \n if (result) {\n hasAnyPermission = true;\n break;\n }\n }\n \n setHasAny(hasAnyPermission);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setHasAny(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkAnyPermission();\n }, [checkAnyPermission]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n hasAny,\n isLoading,\n error,\n refetch: checkAnyPermission\n }), [hasAny, isLoading, error, checkAnyPermission]);\n}\n\n/**\n * Hook to check if user has all of the specified permissions\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @param permissions - Array of permissions to check\n * @param useCache - Whether to use cached results\n * @returns Whether user has all of the permissions\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { hasAll, isLoading, error } = useHasAllPermissions(\n * userId, \n * scope, \n * ['read:users', 'create:users', 'update:users']\n * );\n * \n * if (isLoading) return <div>Checking permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return hasAll ? <FullUserManagementPanel /> : <div>Insufficient permissions</div>;\n * }\n * ```\n */\nexport function useHasAllPermissions(\n userId: UUID, \n scope: Scope, \n permissions: Permission[],\n useCache: boolean = true\n): {\n hasAll: boolean;\n isLoading: boolean;\n error: Error | null;\n refetch: () => Promise<void>;\n} {\n const [hasAll, setHasAll] = useState<boolean>(false);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const checkAllPermissions = useCallback(async () => {\n if (!userId || permissions.length === 0) {\n setHasAll(false);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n let hasAllPermissions = true;\n \n for (const permission of permissions) {\n const result = useCache \n ? await isPermittedCached({ userId, scope, permission })\n : await isPermitted({ userId, scope, permission });\n \n if (!result) {\n hasAllPermissions = false;\n break;\n }\n }\n \n setHasAll(hasAllPermissions);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to check permissions'));\n setHasAll(false);\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId, permissions, useCache]);\n\n useEffect(() => {\n checkAllPermissions();\n }, [checkAllPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n hasAll,\n isLoading,\n error,\n refetch: checkAllPermissions\n }), [hasAll, isLoading, error, checkAllPermissions]);\n}\n\n/**\n * Hook to get cached permissions with TTL management\n * \n * @param userId - User ID\n * @param scope - Scope for permission checking\n * @returns Cached permission state and methods\n * \n * @example\n * ```tsx\n * function MyComponent() {\n * const { permissions, isLoading, error, invalidateCache } = useCachedPermissions(userId, scope);\n * \n * if (isLoading) return <div>Loading cached permissions...</div>;\n * if (error) return <div>Error: {error.message}</div>;\n * \n * return (\n * <div>\n * {permissions['read:users'] && <UserList />}\n * <button onClick={invalidateCache}>Refresh Permissions</button>\n * </div>\n * );\n * }\n * ```\n */\nexport function useCachedPermissions(userId: UUID, scope: Scope): {\n permissions: PermissionMap;\n isLoading: boolean;\n error: Error | null;\n invalidateCache: () => void;\n refetch: () => Promise<void>;\n} {\n const [permissions, setPermissions] = useState<PermissionMap>({} as PermissionMap);\n const [isLoading, setIsLoading] = useState(true);\n const [error, setError] = useState<Error | null>(null);\n\n const fetchCachedPermissions = useCallback(async () => {\n if (!userId) {\n setPermissions({} as PermissionMap);\n setIsLoading(false);\n return;\n }\n\n try {\n setIsLoading(true);\n setError(null);\n \n const permissionMap = await getPermissionMap({ userId, scope });\n setPermissions(permissionMap);\n } catch (err) {\n setError(err instanceof Error ? err : new Error('Failed to fetch cached permissions'));\n } finally {\n setIsLoading(false);\n }\n }, [userId, scope.organisationId, scope.eventId, scope.appId]);\n\n const invalidateCache = useCallback(() => {\n // This would typically invalidate the cache in the actual implementation\n // For now, we'll just refetch\n fetchCachedPermissions();\n }, [fetchCachedPermissions]);\n\n useEffect(() => {\n fetchCachedPermissions();\n }, [fetchCachedPermissions]);\n\n // Memoize the return object to prevent unnecessary re-renders\n return useMemo(() => ({\n permissions,\n isLoading,\n error,\n invalidateCache,\n refetch: fetchCachedPermissions\n }), [permissions, isLoading, error, invalidateCache, fetchCachedPermissions]);\n}\n","/**\n * @file useResourcePermissions Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 1.0.0\n * \n * Hook to check permissions for a specific resource type.\n * This hook centralizes the common pattern of checking create/update/delete/read\n * permissions, eliminating ~30 lines of boilerplate code per hook usage.\n * \n * @example\n * ```tsx\n * import { useResourcePermissions } from '@jmruthers/pace-core/rbac';\n * \n * function ContactsHook() {\n * const { canCreate, canUpdate, canDelete } = useResourcePermissions('contacts');\n * \n * const addContact = async (data: ContactData) => {\n * if (!canCreate('contacts')) {\n * throw new Error(\"Permission denied: You do not have permission to create contacts.\");\n * }\n * // ... perform mutation\n * };\n * }\n * ```\n * \n * @example\n * ```tsx\n * // With read permissions enabled\n * const { canRead } = useResourcePermissions('contacts', { enableRead: true });\n * \n * if (!canRead('contacts')) {\n * return <PermissionDenied />;\n * }\n * ```\n * \n * @security\n * - Requires organisation context (handled by useResolvedScope)\n * - All permission checks are scoped to the current organisation/event/app context\n * - Missing user context results in all permissions being denied\n */\n\nimport { useMemo } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport { useOrganisations } from '../../hooks/useOrganisations';\nimport { useEvents } from '../../hooks/useEvents';\nimport { useResolvedScope } from './useResolvedScope';\nimport { useCan } from './usePermissions';\nimport type { Scope } from '../types';\n\nexport interface UseResourcePermissionsOptions {\n /** Whether to check read permissions (default: false) */\n enableRead?: boolean;\n /** Whether scope resolution is required (default: true) */\n requireScope?: boolean;\n}\n\nexport interface ResourcePermissions {\n /** Check if user can create resources of this type */\n canCreate: (resource: string) => boolean;\n /** Check if user can update resources of this type */\n canUpdate: (resource: string) => boolean;\n /** Check if user can delete resources of this type */\n canDelete: (resource: string) => boolean;\n /** Check if user can read resources of this type */\n canRead: (resource: string) => boolean;\n /** The resolved scope object (for advanced use cases) */\n scope: Scope;\n /** Whether any permission check is currently loading */\n isLoading: boolean;\n /** Error from any permission check or scope resolution */\n error: Error | null;\n}\n\n/**\n * Hook to check permissions for a specific resource\n * \n * This hook encapsulates the common pattern of checking create/update/delete/read\n * permissions for a resource type. It handles scope resolution, user context,\n * and provides a simple API for permission checking.\n * \n * **Page Permission Support:**\n * When an `appId` is available in the resolved scope, the resource name is passed\n * as `pageId` to enable page-based permission checks. This allows the hook to work\n * with both resource-based permissions (when appId is not available) and page-based\n * permissions (when appId is available and the resource is a registered page).\n * \n * The RPC function `rbac_check_permission_simplified` will automatically resolve\n * the page name to a page ID and check page permissions if the resource matches\n * a registered page in `rbac_app_pages`. If the resource is not a registered page,\n * it will fall back to resource-based permission checking.\n * \n * @param resource - The resource name (e.g., 'contacts', 'risks', 'planning')\n * Can be a resource name or a page name registered in rbac_app_pages\n * @param options - Optional configuration\n * @param options.enableRead - Whether to check read permissions (default: false)\n * @param options.requireScope - Whether scope resolution is required (default: true)\n * @returns Object with permission check functions and scope\n * \n * @example\n * ```tsx\n * function useContacts() {\n * const { canCreate, canUpdate, canDelete } = useResourcePermissions('contacts');\n * \n * const addContact = async (data: ContactData) => {\n * if (!canCreate('contacts')) {\n * throw new Error(\"Permission denied\");\n * }\n * // ... perform mutation\n * };\n * }\n * ```\n * \n * @example\n * ```tsx\n * // Works with page names when appId is available in scope\n * function usePlanning() {\n * const { canCreate, canUpdate, canDelete } = useResourcePermissions('planning');\n * \n * // Will check page permissions if 'planning' is registered in rbac_app_pages\n * // Falls back to resource permissions if not a registered page\n * const deleteItem = async (id: string) => {\n * if (!canDelete('planning')) {\n * throw new Error(\"Permission denied\");\n * }\n * // ... perform deletion\n * };\n * }\n * ```\n */\nexport function useResourcePermissions(\n resource: string,\n options: UseResourcePermissionsOptions = {}\n): ResourcePermissions {\n const { enableRead = false, requireScope = true } = options;\n\n // Get user and supabase client from UnifiedAuth\n const { user, supabase } = useUnifiedAuth();\n \n // Get selected organisation\n const { selectedOrganisation } = useOrganisations();\n \n // Get selected event (optional - wrap in try/catch)\n let selectedEvent: { event_id: string } | null = null;\n try {\n const eventsContext = useEvents();\n selectedEvent = eventsContext.selectedEvent;\n } catch (error) {\n // Event provider not available - continue without event context\n // This is expected in some apps that don't use events\n }\n\n // Resolve scope for permission checks\n const { resolvedScope, isLoading: scopeLoading, error: scopeError } = useResolvedScope({\n supabase,\n selectedOrganisationId: selectedOrganisation?.id || null,\n selectedEventId: selectedEvent?.event_id || null\n });\n\n // Create fallback scope if resolvedScope is not available\n const scope: Scope = resolvedScope || {\n organisationId: selectedOrganisation?.id || '',\n eventId: selectedEvent?.event_id || undefined,\n appId: undefined\n };\n\n // If we have an appId in scope, pass the resource name as pageId to enable page permission checks\n // The RPC function rbac_check_permission_simplified will resolve the page name to a page ID\n // and check page permissions if the resource is a registered page\n // This allows useResourcePermissions to work with both resource-based and page-based permissions\n const pageId = scope.appId ? resource : undefined;\n\n // Permission checks for create, update, delete\n const { can: canCreateResult, isLoading: createLoading, error: createError } = useCan(\n user?.id || '',\n scope,\n `create:${resource}` as const,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true // useCache\n );\n\n const { can: canUpdateResult, isLoading: updateLoading, error: updateError } = useCan(\n user?.id || '',\n scope,\n `update:${resource}` as const,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true // useCache\n );\n\n const { can: canDeleteResult, isLoading: deleteLoading, error: deleteError } = useCan(\n user?.id || '',\n scope,\n `delete:${resource}` as const,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true // useCache\n );\n\n // Optional read permission check\n const { can: canReadResult, isLoading: readLoading, error: readError } = useCan(\n user?.id || '',\n scope,\n `read:${resource}` as const,\n pageId, // Pass resource name as pageId when appId is available to enable page permission checks\n true // useCache\n );\n\n // Aggregate loading states - any permission check or scope resolution loading\n const isLoading = useMemo(() => {\n return scopeLoading || createLoading || updateLoading || deleteLoading || (enableRead && readLoading);\n }, [scopeLoading, createLoading, updateLoading, deleteLoading, readLoading, enableRead]);\n\n // Aggregate errors - prefer scope error, then any permission error\n const error = useMemo(() => {\n if (scopeError) return scopeError;\n if (createError) return createError;\n if (updateError) return updateError;\n if (deleteError) return deleteError;\n if (enableRead && readError) return readError;\n return null;\n }, [scopeError, createError, updateError, deleteError, readError, enableRead]);\n\n // Return wrapper functions that take resource name and return permission result\n // Note: The resource parameter in the function is for consistency with the API,\n // but we're checking permissions for the resource passed to the hook\n return useMemo(() => ({\n canCreate: (res: string) => {\n // For now, we only check the resource passed to the hook\n // Future enhancement could support checking different resources\n if (res !== resource) {\n return false;\n }\n return canCreateResult;\n },\n canUpdate: (res: string) => {\n if (res !== resource) {\n return false;\n }\n return canUpdateResult;\n },\n canDelete: (res: string) => {\n if (res !== resource) {\n return false;\n }\n return canDeleteResult;\n },\n canRead: (res: string) => {\n if (!enableRead) {\n return true; // If read checking is disabled, allow read\n }\n if (res !== resource) {\n return false;\n }\n return canReadResult;\n },\n scope,\n isLoading,\n error\n }), [\n resource,\n canCreateResult,\n canUpdateResult,\n canDeleteResult,\n canReadResult,\n enableRead,\n scope,\n isLoading,\n error\n ]);\n}\n\n","/**\n * @file RBAC Role Management Hook\n * @package @jmruthers/pace-core\n * @module RBAC/Hooks\n * @since 2.1.0\n *\n * React hook for managing RBAC roles safely using RPC functions.\n * This hook provides a secure, type-safe interface for granting and revoking roles\n * that ensures proper audit trails and security checks.\n *\n * @example\n * ```tsx\n * import { useRoleManagement } from '@jmruthers/pace-core/rbac';\n *\n * function UserRolesComponent() {\n * const { revokeEventAppRole, grantEventAppRole, isLoading, error } = useRoleManagement();\n *\n * const handleRevokeRole = async (roleId: string, roleData: EventAppRoleData) => {\n * const result = await revokeEventAppRole({\n * userId: roleData.user_id,\n * organisationId: roleData.organisation_id,\n * eventId: roleData.event_id,\n * appId: roleData.app_id,\n * role: roleData.role\n * });\n *\n * if (result.success) {\n * toast({ title: 'Role revoked successfully' });\n * } else {\n * toast({ title: 'Failed to revoke role', variant: 'destructive' });\n * }\n * };\n *\n * return <button onClick={() => handleRevokeRole(roleId, roleData)}>Revoke Role</button>;\n * }\n * ```\n */\n\nimport { useState, useCallback } from 'react';\nimport { useUnifiedAuth } from '../../providers/services/UnifiedAuthProvider';\nimport type { UUID } from '../types';\n\nexport interface EventAppRoleData {\n user_id: UUID;\n organisation_id: UUID;\n event_id: string;\n app_id: UUID;\n role: 'viewer' | 'participant' | 'planner' | 'event_admin';\n}\n\nexport interface RevokeEventAppRoleParams extends EventAppRoleData {\n revoked_by?: UUID;\n}\n\nexport interface GrantEventAppRoleParams extends EventAppRoleData {\n granted_by?: UUID;\n valid_from?: string;\n valid_to?: string | null;\n}\n\nexport interface RoleManagementResult {\n success: boolean;\n message?: string;\n error?: string;\n roleId?: UUID;\n}\n\nexport function useRoleManagement() {\n const { user, supabase } = useUnifiedAuth();\n const [isLoading, setIsLoading] = useState(false);\n const [error, setError] = useState<Error | null>(null);\n\n if (!supabase) {\n throw new Error('useRoleManagement requires a Supabase client. Ensure UnifiedAuthProvider is configured.');\n }\n\n /**\n * Revoke an event app role using the secure RPC function\n * \n * This function uses the `revoke_event_app_role` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (revoked_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role revocation parameters\n * @returns Promise resolving to operation result\n */\n const revokeEventAppRole = useCallback(async (\n params: RevokeEventAppRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('revoke_event_app_role', {\n p_user_id: params.user_id,\n p_organisation_id: params.organisation_id,\n p_event_id: params.event_id,\n p_app_id: params.app_id,\n p_role: params.role,\n p_revoked_by: params.revoked_by || user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to revoke role');\n }\n\n return {\n success: data === true,\n message: data === true ? 'Role revoked successfully' : 'No role found to revoke',\n error: data === false ? 'No matching role found' : undefined\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id]);\n\n /**\n * Grant an event app role using the secure RPC function\n * \n * This function uses the `grant_event_app_role` RPC which:\n * - Runs with SECURITY DEFINER privileges\n * - Includes proper permission checks\n * - Automatically populates audit fields (granted_by, timestamps)\n * - Complies with Row-Level Security policies\n * \n * @param params - Role grant parameters\n * @returns Promise resolving to operation result with role ID\n */\n const grantEventAppRole = useCallback(async (\n params: GrantEventAppRoleParams\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n const { data, error: rpcError } = await supabase.rpc('grant_event_app_role', {\n p_user_id: params.user_id,\n p_organisation_id: params.organisation_id,\n p_event_id: params.event_id,\n p_app_id: params.app_id,\n p_role: params.role,\n p_granted_by: params.granted_by || user?.id || undefined,\n p_valid_from: params.valid_from,\n p_valid_to: params.valid_to\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to grant role');\n }\n\n if (!data) {\n return {\n success: false,\n error: 'Failed to grant role - no role ID returned'\n };\n }\n\n return {\n success: true,\n message: 'Role granted successfully',\n roleId: data as UUID\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id]);\n\n /**\n * Revoke an event app role by role ID (alternative method)\n * \n * This fetches the role by ID first to get the required context (role name, event_id, app_id),\n * then uses the unified `rbac_role_revoke` function to revoke it.\n * \n * @param roleId - The role ID to revoke\n * @returns Promise resolving to operation result\n */\n const revokeRoleById = useCallback(async (\n roleId: UUID\n ): Promise<RoleManagementResult> => {\n setIsLoading(true);\n setError(null);\n\n try {\n // First, fetch the role by ID to get the required context\n const { data: roleData, error: fetchError } = await supabase\n .from('rbac_event_app_roles')\n .select('user_id, role, event_id, app_id')\n .eq('id', roleId)\n .single();\n\n if (fetchError || !roleData) {\n throw new Error(fetchError?.message || 'Role not found');\n }\n\n // Construct context_id in the format required by rbac_role_revoke: \"event_id:app_id\"\n const contextId = `${roleData.event_id}:${roleData.app_id}`;\n\n // Now call rbac_role_revoke with the required parameters\n const { data, error: rpcError } = await supabase.rpc('rbac_role_revoke', {\n p_user_id: roleData.user_id,\n p_role_type: 'event_app',\n p_role_name: roleData.role,\n p_context_id: contextId,\n p_revoked_by: user?.id || undefined\n });\n\n if (rpcError) {\n throw new Error(rpcError.message || 'Failed to revoke role');\n }\n\n // rbac_role_revoke returns a table with success, message, revoked_count, error_code\n const result = Array.isArray(data) && data.length > 0 ? data[0] : null;\n\n return {\n success: result?.success === true,\n message: result?.message || undefined,\n error: result?.success === false ? (result?.message || result?.error_code || 'Unknown error') : undefined\n };\n } catch (err) {\n const errorMessage = err instanceof Error ? err.message : 'Unknown error occurred';\n setError(err instanceof Error ? err : new Error(errorMessage));\n return {\n success: false,\n error: errorMessage\n };\n } finally {\n setIsLoading(false);\n }\n }, [user?.id, supabase]);\n\n return {\n revokeEventAppRole,\n grantEventAppRole,\n revokeRoleById,\n isLoading,\n error\n };\n}\n\n"],"mappings":"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","names":["useEffect","useState","useState","useEffect","error","useState","useEffect","useCallback","useMemo","useRef","useState","useRef","useEffect","useCallback","logger","useMemo","useMemo","error","useMemo","useState","useCallback"]}
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/utils/validation/htmlSanitization.ts"],"sourcesContent":["/**\n * @file HTML Sanitization Utilities\n * @package @jmruthers/pace-core\n * @module Utils/Validation/HTMLSanitization\n * @since 0.4.36\n * \n * Utilities for safely rendering HTML content.\n * Provides sanitization and validation for basic HTML elements.\n */\n\n/**\n * Allowed HTML tags for safe rendering\n */\nconst ALLOWED_TAGS = [\n 'p', 'div', 'span', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',\n 'strong', 'em', 'b', 'i', 'u', 's', 'mark', 'small', 'sub', 'sup',\n 'ul', 'ol', 'li', 'dl', 'dt', 'dd',\n 'blockquote', 'pre', 'code', 'kbd', 'samp',\n 'a', 'br', 'hr',\n 'table', 'thead', 'tbody', 'tfoot', 'tr', 'th', 'td',\n 'img', 'figure', 'figcaption',\n 'section', 'article', 'aside', 'header', 'footer', 'main', 'nav',\n 'details', 'summary'\n] as const;\n\n/**\n * Allowed HTML attributes for safe rendering\n */\nconst ALLOWED_ATTRIBUTES = [\n 'id', 'class', 'style', 'title', 'lang', 'dir',\n 'href', 'target', 'rel', 'download',\n 'src', 'alt', 'width', 'height', 'loading',\n 'colspan', 'rowspan', 'scope', 'headers',\n 'open', 'datetime', 'cite'\n] as const;\n\n/**\n * Basic HTML sanitization function using regex-based approach\n * Removes potentially dangerous elements and attributes while preserving basic formatting\n * This approach is more reliable in SSR environments and doesn't require DOM manipulation\n * \n * @param html - The HTML string to sanitize\n * @returns Sanitized HTML string safe for rendering\n * \n * @example\n * ```tsx\n * const safeHtml = sanitizeHtml('<p>Hello <strong>world</strong>!</p>');\n * // Returns: '<p>Hello <strong>world</strong>!</p>'\n * \n * const dangerousHtml = sanitizeHtml('<script>alert(\"xss\")</script><p>Safe content</p>');\n * // Returns: '<p>Safe content</p>'\n * ```\n */\nexport function sanitizeHtml(html: string): string {\n if (!html || typeof html !== 'string') {\n return '';\n }\n\n // Basic safety: just remove script tags and dangerous attributes\n let sanitized = html\n // Remove script tags (including self-closing and malformed)\n .replace(/<script\\b[^>]*>.*?<\\/script>/gi, '')\n .replace(/<script\\b[^>]*\\/>/gi, '')\n // Remove iframe tags (including self-closing and malformed)\n .replace(/<iframe\\b[^>]*>.*?<\\/iframe>/gi, '')\n .replace(/<iframe\\b[^>]*\\/>/gi, '')\n // Remove object tags (including self-closing and malformed)\n .replace(/<object\\b[^>]*>.*?<\\/object>/gi, '')\n .replace(/<object\\b[^>]*\\/>/gi, '')\n // Remove embed tags (including self-closing)\n .replace(/<embed\\b[^>]*\\/?>/gi, '')\n // Remove form tags (including self-closing and malformed)\n .replace(/<form\\b[^>]*>.*?<\\/form>/gi, '')\n .replace(/<form\\b[^>]*\\/>/gi, '')\n // Remove input tags (including self-closing)\n .replace(/<input\\b[^>]*\\/?>/gi, '')\n // Remove button tags (including self-closing and malformed)\n .replace(/<button\\b[^>]*>.*?<\\/button>/gi, '')\n .replace(/<button\\b[^>]*\\/>/gi, '')\n // Remove event handlers from any remaining tags - correct pattern\n .replace(/\\s*on\\w+\\s*=\\s*[\"'][^\"']*[\"']/gi, '')\n // Remove javascript: protocols - correct pattern\n .replace(/javascript:[^\"'\\s>]*/gi, '')\n // Remove data: protocols - correct pattern\n .replace(/data:[^\"'\\s>]*/gi, '');\n\n return sanitized;\n}\n\n/**\n * Validates if HTML content is safe for rendering\n * \n * @param html - The HTML string to validate\n * @returns Object with validation result and any warnings\n * \n * @example\n * ```tsx\n * const validation = validateHtml('<p>Safe content</p>');\n * console.log(validation.isValid); // true\n * console.log(validation.warnings); // []\n * ```\n */\nexport function validateHtml(html: string): { isValid: boolean; warnings: string[] } {\n const warnings: string[] = [];\n \n if (!html || typeof html !== 'string') {\n return { isValid: false, warnings: ['HTML content must be a non-empty string'] };\n }\n\n // Check for potentially dangerous patterns\n const dangerousPatterns = [\n { pattern: /<script\\b[^>]*>.*?<\\/script>/gi, message: 'Script tags are not allowed' },\n { pattern: /<script\\b[^>]*\\/>/gi, message: 'Script tags are not allowed' },\n { pattern: /<iframe\\b[^>]*>.*?<\\/iframe>/gi, message: 'Iframe tags are not allowed' },\n { pattern: /<iframe\\b[^>]*\\/>/gi, message: 'Iframe tags are not allowed' },\n { pattern: /<object\\b[^>]*>.*?<\\/object>/gi, message: 'Object tags are not allowed' },\n { pattern: /<object\\b[^>]*\\/>/gi, message: 'Object tags are not allowed' },\n { pattern: /<embed\\b[^>]*\\/?>/gi, message: 'Embed tags are not allowed' },\n { pattern: /<form\\b[^>]*>.*?<\\/form>/gi, message: 'Form tags are not allowed' },\n { pattern: /<form\\b[^>]*\\/>/gi, message: 'Form tags are not allowed' },\n { pattern: /<input\\b[^>]*\\/?>/gi, message: 'Input tags are not allowed' },\n { pattern: /<button\\b[^>]*>.*?<\\/button>/gi, message: 'Button tags are not allowed' },\n { pattern: /<button\\b[^>]*\\/>/gi, message: 'Button tags are not allowed' },\n { pattern: /on\\w+\\s*=/gi, message: 'Event handlers are not allowed' },\n { pattern: /javascript:/gi, message: 'JavaScript protocols are not allowed' },\n { pattern: /data:/gi, message: 'Data protocols are not allowed' }\n ];\n\n dangerousPatterns.forEach(({ pattern, message }) => {\n if (pattern.test(html)) {\n warnings.push(message);\n }\n });\n\n return {\n isValid: warnings.length === 0,\n warnings\n };\n}\n\n/**\n * Safely renders HTML content with sanitization\n * \n * @param html - The HTML string to render\n * @param options - Rendering options\n * @returns Object with sanitized HTML and validation info\n * \n * @example\n * ```tsx\n * const result = renderSafeHtml('<p>Hello <strong>world</strong>!</p>');\n * console.log(result.html); // Sanitized HTML\n * console.log(result.isValid); // true\n * ```\n */\nexport function renderSafeHtml(\n html: string, \n options: { \n strict?: boolean; \n logWarnings?: boolean;\n } = {}\n): { \n html: string; \n isValid: boolean; \n warnings: string[] \n} {\n const { strict = true, logWarnings = false } = options;\n \n const validation = validateHtml(html);\n const sanitizedHtml = sanitizeHtml(html);\n \n if (logWarnings && validation.warnings.length > 0) {\n // Use logger if needed, but this is controlled by logWarnings option\n // For now, keep console.warn as it's only called when explicitly requested\n // via logWarnings option, which is typically for debugging\n console.warn('HTML content warnings:', validation.warnings);\n }\n \n return {\n html: sanitizedHtml,\n isValid: validation.isValid,\n warnings: validation.warnings\n };\n}\n\n"],"mappings":";AAqDO,SAAS,aAAa,MAAsB;AACjD,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO;AAAA,EACT;AAGA,MAAI,YAAY,KAEb,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,8BAA8B,EAAE,EACxC,QAAQ,qBAAqB,EAAE,EAE/B,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,kCAAkC,EAAE,EAC5C,QAAQ,uBAAuB,EAAE,EAEjC,QAAQ,mCAAmC,EAAE,EAE7C,QAAQ,0BAA0B,EAAE,EAEpC,QAAQ,oBAAoB,EAAE;AAEjC,SAAO;AACT;AAeO,SAAS,aAAa,MAAwD;AACnF,QAAM,WAAqB,CAAC;AAE5B,MAAI,CAAC,QAAQ,OAAO,SAAS,UAAU;AACrC,WAAO,EAAE,SAAS,OAAO,UAAU,CAAC,yCAAyC,EAAE;AAAA,EACjF;AAGA,QAAM,oBAAoB;AAAA,IACxB,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,uBAAuB,SAAS,6BAA6B;AAAA,IACxE,EAAE,SAAS,8BAA8B,SAAS,4BAA4B;AAAA,IAC9E,EAAE,SAAS,qBAAqB,SAAS,4BAA4B;AAAA,IACrE,EAAE,SAAS,uBAAuB,SAAS,6BAA6B;AAAA,IACxE,EAAE,SAAS,kCAAkC,SAAS,8BAA8B;AAAA,IACpF,EAAE,SAAS,uBAAuB,SAAS,8BAA8B;AAAA,IACzE,EAAE,SAAS,eAAe,SAAS,iCAAiC;AAAA,IACpE,EAAE,SAAS,iBAAiB,SAAS,uCAAuC;AAAA,IAC5E,EAAE,SAAS,WAAW,SAAS,iCAAiC;AAAA,EAClE;AAEA,oBAAkB,QAAQ,CAAC,EAAE,SAAS,QAAQ,MAAM;AAClD,QAAI,QAAQ,KAAK,IAAI,GAAG;AACtB,eAAS,KAAK,OAAO;AAAA,IACvB;AAAA,EACF,CAAC;AAED,SAAO;AAAA,IACL,SAAS,SAAS,WAAW;AAAA,IAC7B;AAAA,EACF;AACF;AAgBO,SAAS,eACd,MACA,UAGI,CAAC,GAKL;AACA,QAAM,EAAE,SAAS,MAAM,cAAc,MAAM,IAAI;AAE/C,QAAM,aAAa,aAAa,IAAI;AACpC,QAAM,gBAAgB,aAAa,IAAI;AAEvC,MAAI,eAAe,WAAW,SAAS,SAAS,GAAG;AAIjD,YAAQ,KAAK,0BAA0B,WAAW,QAAQ;AAAA,EAC5D;AAEA,SAAO;AAAA,IACL,MAAM;AAAA,IACN,SAAS,WAAW;AAAA,IACpB,UAAU,WAAW;AAAA,EACvB;AACF;","names":[]}