@jmruthers/pace-core 0.5.193 → 0.6.2

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 (577) hide show
  1. package/CHANGELOG.md +62 -0
  2. package/README.md +7 -1
  3. package/cursor-rules/00-pace-core-compliance.mdc +299 -0
  4. package/cursor-rules/01-standards-compliance.mdc +244 -0
  5. package/cursor-rules/02-project-structure.mdc +200 -0
  6. package/cursor-rules/03-solid-principles.mdc +222 -0
  7. package/cursor-rules/04-testing-standards.mdc +268 -0
  8. package/cursor-rules/05-bug-reports-and-features.mdc +246 -0
  9. package/cursor-rules/06-code-quality.mdc +309 -0
  10. package/cursor-rules/07-tech-stack-compliance.mdc +214 -0
  11. package/cursor-rules/08-markup-quality.mdc +452 -0
  12. package/cursor-rules/CHANGELOG.md +119 -0
  13. package/cursor-rules/README.md +192 -0
  14. package/dist/{AuthService-DjnJHDtC.d.ts → AuthService-BPvc3Ka0.d.ts} +54 -0
  15. package/dist/{DataTable-Be6dH_dR.d.ts → DataTable-BMRU8a1j.d.ts} +34 -2
  16. package/dist/{DataTable-5FU7IESH.js → DataTable-TPTKCX4D.js} +10 -9
  17. package/dist/{PublicPageProvider-C0Sm_e5k.d.ts → PublicPageProvider-DC6kCaqf.d.ts} +385 -261
  18. package/dist/{UnifiedAuthProvider-RGJTDE2C.js → UnifiedAuthProvider-CH6Z342H.js} +3 -3
  19. package/dist/{UnifiedAuthProvider-185Ih4dj.d.ts → UnifiedAuthProvider-CVcTjx-d.d.ts} +29 -0
  20. package/dist/{api-N774RPUA.js → api-MVVQZLJI.js} +2 -2
  21. package/dist/{chunk-KNC55RTG.js → chunk-24UVZUZG.js} +90 -54
  22. package/dist/chunk-24UVZUZG.js.map +1 -0
  23. package/dist/{chunk-HWIIPPNI.js → chunk-2UOI2FG5.js} +20 -20
  24. package/dist/chunk-2UOI2FG5.js.map +1 -0
  25. package/dist/{chunk-E3SPN4VZ 5.js → chunk-3XC4CPTD.js} +4345 -3986
  26. package/dist/chunk-3XC4CPTD.js.map +1 -0
  27. package/dist/{chunk-7EQTDTTJ.js → chunk-6J4GEEJR.js} +172 -45
  28. package/dist/chunk-6J4GEEJR.js.map +1 -0
  29. package/dist/{chunk-6C4YBBJM 5.js → chunk-6SOIHG6Z.js} +1 -1
  30. package/dist/chunk-6SOIHG6Z.js.map +1 -0
  31. package/dist/{chunk-7FLMSG37.js → chunk-EHMR7VYL.js} +25 -25
  32. package/dist/chunk-EHMR7VYL.js.map +1 -0
  33. package/dist/{chunk-I7PSE6JW.js → chunk-F2IMUDXZ.js} +2 -75
  34. package/dist/chunk-F2IMUDXZ.js.map +1 -0
  35. package/dist/{chunk-QWWZ5CAQ.js → chunk-FFQEQTNW.js} +7 -9
  36. package/dist/chunk-FFQEQTNW.js.map +1 -0
  37. package/dist/chunk-FMUCXFII.js +76 -0
  38. package/dist/chunk-FMUCXFII.js.map +1 -0
  39. package/dist/{chunk-HW3OVDUF.js → chunk-J36DSWQK.js} +1 -1
  40. package/dist/{chunk-HW3OVDUF.js.map → chunk-J36DSWQK.js.map} +1 -1
  41. package/dist/{chunk-SQGMNID3.js → chunk-L4OXEN46.js} +4 -5
  42. package/dist/chunk-L4OXEN46.js.map +1 -0
  43. package/dist/{chunk-R77UEZ4E 3.js → chunk-M43Y4SSO.js} +1 -1
  44. package/dist/chunk-M43Y4SSO.js.map +1 -0
  45. package/dist/{chunk-IIELH4DL.js → chunk-MMZ7JXPU.js} +60 -223
  46. package/dist/chunk-MMZ7JXPU.js.map +1 -0
  47. package/dist/{chunk-NOAYCWCX 5.js → chunk-NECFR5MM.js} +394 -312
  48. package/dist/chunk-NECFR5MM.js.map +1 -0
  49. package/dist/{chunk-BC4IJKSL.js → chunk-SFZUDBL5.js} +40 -4
  50. package/dist/chunk-SFZUDBL5.js.map +1 -0
  51. package/dist/{chunk-XNXXZ43G.js → chunk-XWQCNGTQ.js} +748 -364
  52. package/dist/chunk-XWQCNGTQ.js.map +1 -0
  53. package/dist/components.d.ts +6 -6
  54. package/dist/components.js +15 -12
  55. package/dist/components.js.map +1 -1
  56. package/dist/{functions-D_kgHktt.d.ts → functions-DHebl8-F.d.ts} +1 -1
  57. package/dist/hooks.d.ts +59 -126
  58. package/dist/hooks.js +19 -28
  59. package/dist/hooks.js.map +1 -1
  60. package/dist/index.d.ts +63 -16
  61. package/dist/index.js +23 -24
  62. package/dist/index.js.map +1 -1
  63. package/dist/providers.d.ts +21 -3
  64. package/dist/providers.js +2 -2
  65. package/dist/rbac/index.d.ts +146 -115
  66. package/dist/rbac/index.js +8 -11
  67. package/dist/theming/runtime.d.ts +1 -13
  68. package/dist/theming/runtime.js +1 -1
  69. package/dist/{timezone-_pgH8qrY.d.ts → timezone-CHhWg6b4.d.ts} +3 -10
  70. package/dist/{types-UU913iLA.d.ts → types-BeoeWV5I.d.ts} +8 -0
  71. package/dist/{types-CEpcvwwF.d.ts → types-CkbwOr4Y.d.ts} +6 -0
  72. package/dist/types.d.ts +2 -2
  73. package/dist/{usePublicRouteParams-TZe0gy-4.d.ts → usePublicRouteParams-1oMokgLF.d.ts} +34 -4
  74. package/dist/{useToast-C8gR5ir4.d.ts → useToast-AyaT-x7p.d.ts} +2 -2
  75. package/dist/utils.d.ts +4 -5
  76. package/dist/utils.js +15 -15
  77. package/dist/utils.js.map +1 -1
  78. package/docs/api/README.md +7 -1
  79. package/docs/api/classes/ColumnFactory.md +8 -8
  80. package/docs/api/classes/InvalidScopeError.md +4 -4
  81. package/docs/api/classes/Logger.md +1 -1
  82. package/docs/api/classes/MissingUserContextError.md +4 -4
  83. package/docs/api/classes/OrganisationContextRequiredError.md +4 -4
  84. package/docs/api/classes/PermissionDeniedError.md +4 -4
  85. package/docs/api/classes/RBACAuditManager.md +1 -1
  86. package/docs/api/classes/RBACCache.md +1 -1
  87. package/docs/api/classes/RBACEngine.md +1 -1
  88. package/docs/api/classes/RBACError.md +4 -4
  89. package/docs/api/classes/RBACNotInitializedError.md +4 -4
  90. package/docs/api/classes/SecureSupabaseClient.md +18 -15
  91. package/docs/api/classes/StorageUtils.md +1 -1
  92. package/docs/api/enums/FileCategory.md +1 -1
  93. package/docs/api/enums/LogLevel.md +1 -1
  94. package/docs/api/enums/RBACErrorCode.md +1 -1
  95. package/docs/api/enums/RPCFunction.md +1 -1
  96. package/docs/api/interfaces/AddressFieldProps.md +1 -1
  97. package/docs/api/interfaces/AddressFieldRef.md +1 -1
  98. package/docs/api/interfaces/AggregateConfig.md +4 -4
  99. package/docs/api/interfaces/AutocompleteOptions.md +1 -1
  100. package/docs/api/interfaces/AvatarProps.md +1 -1
  101. package/docs/api/interfaces/BadgeProps.md +9 -2
  102. package/docs/api/interfaces/ButtonProps.md +7 -4
  103. package/docs/api/interfaces/CalendarProps.md +8 -5
  104. package/docs/api/interfaces/CardProps.md +8 -5
  105. package/docs/api/interfaces/ColorPalette.md +1 -1
  106. package/docs/api/interfaces/ColorShade.md +1 -1
  107. package/docs/api/interfaces/ComplianceResult.md +1 -1
  108. package/docs/api/interfaces/DataAccessRecord.md +9 -9
  109. package/docs/api/interfaces/DataRecord.md +1 -1
  110. package/docs/api/interfaces/DataTableAction.md +24 -21
  111. package/docs/api/interfaces/DataTableColumn.md +31 -31
  112. package/docs/api/interfaces/DataTableProps.md +1 -1
  113. package/docs/api/interfaces/DataTableToolbarButton.md +7 -7
  114. package/docs/api/interfaces/DatabaseComplianceResult.md +1 -1
  115. package/docs/api/interfaces/DatabaseIssue.md +1 -1
  116. package/docs/api/interfaces/EmptyStateConfig.md +5 -5
  117. package/docs/api/interfaces/EnhancedNavigationMenuProps.md +1 -1
  118. package/docs/api/interfaces/ErrorBoundaryProps.md +147 -0
  119. package/docs/api/interfaces/ErrorBoundaryProviderProps.md +36 -0
  120. package/docs/api/interfaces/ErrorBoundaryState.md +75 -0
  121. package/docs/api/interfaces/EventAppRoleData.md +1 -1
  122. package/docs/api/interfaces/ExportColumn.md +1 -1
  123. package/docs/api/interfaces/ExportOptions.md +8 -8
  124. package/docs/api/interfaces/FileDisplayProps.md +1 -1
  125. package/docs/api/interfaces/FileMetadata.md +1 -1
  126. package/docs/api/interfaces/FileReference.md +1 -1
  127. package/docs/api/interfaces/FileSizeLimits.md +1 -1
  128. package/docs/api/interfaces/FileUploadOptions.md +1 -1
  129. package/docs/api/interfaces/FileUploadProps.md +26 -23
  130. package/docs/api/interfaces/FooterProps.md +10 -8
  131. package/docs/api/interfaces/FormFieldProps.md +10 -10
  132. package/docs/api/interfaces/FormProps.md +1 -1
  133. package/docs/api/interfaces/GrantEventAppRoleParams.md +1 -1
  134. package/docs/api/interfaces/InactivityWarningModalProps.md +1 -1
  135. package/docs/api/interfaces/InputProps.md +7 -4
  136. package/docs/api/interfaces/LabelProps.md +1 -1
  137. package/docs/api/interfaces/LoggerConfig.md +1 -1
  138. package/docs/api/interfaces/LoginFormProps.md +14 -11
  139. package/docs/api/interfaces/NavigationAccessRecord.md +1 -1
  140. package/docs/api/interfaces/NavigationContextType.md +1 -1
  141. package/docs/api/interfaces/NavigationGuardProps.md +1 -1
  142. package/docs/api/interfaces/NavigationItem.md +11 -11
  143. package/docs/api/interfaces/NavigationMenuProps.md +15 -15
  144. package/docs/api/interfaces/NavigationProviderProps.md +1 -1
  145. package/docs/api/interfaces/Organisation.md +1 -1
  146. package/docs/api/interfaces/OrganisationContextType.md +1 -1
  147. package/docs/api/interfaces/OrganisationMembership.md +1 -1
  148. package/docs/api/interfaces/OrganisationProviderProps.md +1 -1
  149. package/docs/api/interfaces/OrganisationSecurityError.md +1 -1
  150. package/docs/api/interfaces/PaceAppLayoutProps.md +30 -27
  151. package/docs/api/interfaces/PaceLoginPageProps.md +6 -4
  152. package/docs/api/interfaces/PageAccessRecord.md +1 -1
  153. package/docs/api/interfaces/PagePermissionContextType.md +1 -1
  154. package/docs/api/interfaces/PagePermissionGuardProps.md +1 -1
  155. package/docs/api/interfaces/PagePermissionProviderProps.md +1 -1
  156. package/docs/api/interfaces/PaletteData.md +1 -1
  157. package/docs/api/interfaces/ParsedAddress.md +1 -1
  158. package/docs/api/interfaces/PermissionEnforcerProps.md +1 -1
  159. package/docs/api/interfaces/ProgressProps.md +1 -1
  160. package/docs/api/interfaces/ProtectedRouteProps.md +7 -26
  161. package/docs/api/interfaces/PublicPageFooterProps.md +9 -9
  162. package/docs/api/interfaces/PublicPageHeaderProps.md +10 -10
  163. package/docs/api/interfaces/PublicPageLayoutProps.md +7 -20
  164. package/docs/api/interfaces/QuickFix.md +1 -1
  165. package/docs/api/interfaces/RBACAccessValidateParams.md +1 -1
  166. package/docs/api/interfaces/RBACAccessValidateResult.md +1 -1
  167. package/docs/api/interfaces/RBACAuditLogParams.md +1 -1
  168. package/docs/api/interfaces/RBACAuditLogResult.md +1 -1
  169. package/docs/api/interfaces/RBACConfig.md +1 -1
  170. package/docs/api/interfaces/RBACContext.md +1 -1
  171. package/docs/api/interfaces/RBACLogger.md +1 -1
  172. package/docs/api/interfaces/RBACPageAccessCheckParams.md +1 -1
  173. package/docs/api/interfaces/RBACPerformanceMetrics.md +1 -1
  174. package/docs/api/interfaces/RBACPermissionCheckParams.md +1 -1
  175. package/docs/api/interfaces/RBACPermissionCheckResult.md +1 -1
  176. package/docs/api/interfaces/RBACPermissionsGetParams.md +1 -1
  177. package/docs/api/interfaces/RBACPermissionsGetResult.md +1 -1
  178. package/docs/api/interfaces/RBACResult.md +1 -1
  179. package/docs/api/interfaces/RBACRoleGrantParams.md +1 -1
  180. package/docs/api/interfaces/RBACRoleGrantResult.md +1 -1
  181. package/docs/api/interfaces/RBACRoleRevokeParams.md +1 -1
  182. package/docs/api/interfaces/RBACRoleRevokeResult.md +1 -1
  183. package/docs/api/interfaces/RBACRoleValidateParams.md +1 -1
  184. package/docs/api/interfaces/RBACRoleValidateResult.md +1 -1
  185. package/docs/api/interfaces/RBACRolesListParams.md +1 -1
  186. package/docs/api/interfaces/RBACRolesListResult.md +1 -1
  187. package/docs/api/interfaces/RBACSessionTrackParams.md +1 -1
  188. package/docs/api/interfaces/RBACSessionTrackResult.md +1 -1
  189. package/docs/api/interfaces/ResourcePermissions.md +1 -1
  190. package/docs/api/interfaces/RevokeEventAppRoleParams.md +1 -1
  191. package/docs/api/interfaces/RoleBasedRouterContextType.md +1 -1
  192. package/docs/api/interfaces/RoleBasedRouterProps.md +1 -1
  193. package/docs/api/interfaces/RoleManagementResult.md +1 -1
  194. package/docs/api/interfaces/RouteAccessRecord.md +1 -1
  195. package/docs/api/interfaces/RouteConfig.md +1 -1
  196. package/docs/api/interfaces/RuntimeComplianceResult.md +1 -1
  197. package/docs/api/interfaces/SecureDataContextType.md +9 -9
  198. package/docs/api/interfaces/SecureDataProviderProps.md +8 -8
  199. package/docs/api/interfaces/SessionRestorationLoaderProps.md +3 -3
  200. package/docs/api/interfaces/SetupIssue.md +1 -1
  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 +3 -3
  215. package/docs/api/interfaces/TextareaProps.md +1 -1
  216. package/docs/api/interfaces/ToastActionElement.md +4 -1
  217. package/docs/api/interfaces/ToastProps.md +1 -1
  218. package/docs/api/interfaces/UnifiedAuthContextType.md +58 -55
  219. package/docs/api/interfaces/UnifiedAuthProviderProps.md +15 -13
  220. package/docs/api/interfaces/UseFormDialogOptions.md +1 -1
  221. package/docs/api/interfaces/UseFormDialogReturn.md +1 -1
  222. package/docs/api/interfaces/UseInactivityTrackerOptions.md +11 -9
  223. package/docs/api/interfaces/UseInactivityTrackerReturn.md +8 -8
  224. package/docs/api/interfaces/UsePublicEventLogoOptions.md +6 -6
  225. package/docs/api/interfaces/UsePublicEventLogoReturn.md +9 -6
  226. package/docs/api/interfaces/UsePublicEventOptions.md +3 -3
  227. package/docs/api/interfaces/UsePublicEventReturn.md +8 -5
  228. package/docs/api/interfaces/UsePublicFileDisplayOptions.md +4 -4
  229. package/docs/api/interfaces/UsePublicFileDisplayReturn.md +12 -9
  230. package/docs/api/interfaces/UsePublicRouteParamsReturn.md +10 -7
  231. package/docs/api/interfaces/UseResolvedScopeOptions.md +1 -1
  232. package/docs/api/interfaces/UseResolvedScopeReturn.md +1 -1
  233. package/docs/api/interfaces/UseResourcePermissionsOptions.md +1 -1
  234. package/docs/api/interfaces/UserEventAccess.md +14 -11
  235. package/docs/api/interfaces/UserMenuProps.md +8 -6
  236. package/docs/api/interfaces/UserProfile.md +1 -1
  237. package/docs/api/modules.md +575 -634
  238. package/docs/architecture/database-schema-requirements.md +161 -0
  239. package/docs/core-concepts/rbac-system.md +3 -3
  240. package/docs/documentation-index.md +2 -4
  241. package/docs/getting-started/cursor-rules.md +263 -0
  242. package/docs/getting-started/installation-guide.md +6 -1
  243. package/docs/getting-started/quick-start.md +6 -1
  244. package/docs/migration/DOCUMENTATION_STRUCTURE.md +441 -0
  245. package/docs/migration/MIGRATION_GUIDE.md +6 -28
  246. package/docs/migration/README.md +52 -6
  247. package/docs/migration/V0.5.190_TO_V0.6.1_MIGRATION.md +1153 -0
  248. package/docs/migration/V0.6.0_REACT_19_MIGRATION.md +227 -0
  249. package/docs/migration/database-changes-december-2025.md +3 -3
  250. package/docs/rbac/event-based-apps.md +1 -1
  251. package/docs/rbac/getting-started.md +1 -1
  252. package/docs/rbac/quick-start.md +1 -1
  253. package/docs/standards/README.md +40 -0
  254. package/docs/troubleshooting/migration.md +4 -4
  255. package/examples/PublicPages/PublicEventPage.tsx +1 -1
  256. package/package.json +12 -6
  257. package/scripts/audit/core/checks/accessibility.cjs +197 -0
  258. package/scripts/audit/core/checks/api-usage.cjs +191 -0
  259. package/scripts/audit/core/checks/bundle.cjs +142 -0
  260. package/scripts/{check-pace-core-compliance.cjs → audit/core/checks/compliance.cjs} +737 -691
  261. package/scripts/audit/core/checks/config.cjs +54 -0
  262. package/scripts/audit/core/checks/coverage.cjs +84 -0
  263. package/scripts/audit/core/checks/dependencies.cjs +454 -0
  264. package/scripts/audit/core/checks/documentation.cjs +203 -0
  265. package/scripts/audit/core/checks/environment.cjs +128 -0
  266. package/scripts/audit/core/checks/error-handling.cjs +299 -0
  267. package/scripts/audit/core/checks/forms.cjs +172 -0
  268. package/scripts/audit/core/checks/heuristics.cjs +68 -0
  269. package/scripts/audit/core/checks/hooks.cjs +334 -0
  270. package/scripts/audit/core/checks/imports.cjs +244 -0
  271. package/scripts/audit/core/checks/performance.cjs +325 -0
  272. package/scripts/audit/core/checks/routes.cjs +117 -0
  273. package/scripts/audit/core/checks/state.cjs +130 -0
  274. package/scripts/audit/core/checks/structure.cjs +65 -0
  275. package/scripts/audit/core/checks/style.cjs +584 -0
  276. package/scripts/audit/core/checks/testing.cjs +122 -0
  277. package/scripts/audit/core/checks/typescript.cjs +61 -0
  278. package/scripts/audit/core/scanner.cjs +199 -0
  279. package/scripts/audit/core/utils.cjs +137 -0
  280. package/scripts/audit/index.cjs +223 -0
  281. package/scripts/audit/reporters/console.cjs +151 -0
  282. package/scripts/audit/reporters/json.cjs +54 -0
  283. package/scripts/audit/reporters/markdown.cjs +124 -0
  284. package/scripts/audit-consuming-app.cjs +86 -0
  285. package/scripts/build-docs/build-decision.js +240 -0
  286. package/scripts/build-docs/cache-utils.js +105 -0
  287. package/scripts/build-docs/content-normalization.js +150 -0
  288. package/scripts/build-docs/file-utils.js +105 -0
  289. package/scripts/build-docs/git-utils.js +86 -0
  290. package/scripts/build-docs/hash-utils.js +116 -0
  291. package/scripts/build-docs/typedoc-runner.js +220 -0
  292. package/scripts/build-docs-incremental.js +77 -913
  293. package/scripts/install-cursor-rules.cjs +236 -0
  294. package/scripts/utils/command-runner.js +16 -11
  295. package/scripts/validate-formats.js +61 -56
  296. package/scripts/validate-master.js +74 -69
  297. package/scripts/validate-pre-publish.js +70 -65
  298. package/src/__tests__/helpers/test-providers.tsx +1 -1
  299. package/src/__tests__/helpers/test-utils.tsx +1 -1
  300. package/src/__tests__/hooks/usePermissions.test.ts +2 -2
  301. package/src/components/Alert/Alert.test.tsx +12 -18
  302. package/src/components/Alert/Alert.tsx +5 -7
  303. package/src/components/Avatar/Avatar.test.tsx +4 -4
  304. package/src/components/Badge/Badge.tsx +16 -4
  305. package/src/components/Button/Button.tsx +27 -4
  306. package/src/components/Calendar/Calendar.tsx +9 -3
  307. package/src/components/Card/Card.tsx +4 -0
  308. package/src/components/Checkbox/Checkbox.test.tsx +12 -12
  309. package/src/components/Checkbox/Checkbox.tsx +2 -2
  310. package/src/components/DataTable/DataTable.test.tsx +57 -93
  311. package/src/components/DataTable/DataTable.tsx +40 -6
  312. package/src/components/DataTable/__tests__/DataTableCore.test-setup.ts +5 -6
  313. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +29 -7
  314. package/src/components/DataTable/__tests__/ssr.strict-mode.test.tsx +12 -12
  315. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +2 -3
  316. package/src/components/DataTable/components/AccessDeniedPage.tsx +17 -26
  317. package/src/components/DataTable/components/ActionButtons.tsx +10 -7
  318. package/src/components/DataTable/components/BulkOperationsDropdown.tsx +2 -2
  319. package/src/components/DataTable/components/ColumnFilter.tsx +10 -0
  320. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +12 -0
  321. package/src/components/DataTable/components/DataTableBody.tsx +8 -0
  322. package/src/components/DataTable/components/DataTableCore.tsx +200 -561
  323. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +11 -0
  324. package/src/components/DataTable/components/DataTableLayout.tsx +559 -0
  325. package/src/components/DataTable/components/DataTableModals.tsx +9 -1
  326. package/src/components/DataTable/components/DataTableToolbar.tsx +8 -0
  327. package/src/components/DataTable/components/DraggableColumnHeader.tsx +12 -0
  328. package/src/components/DataTable/components/EditFields.tsx +307 -0
  329. package/src/components/DataTable/components/EditableRow.tsx +9 -1
  330. package/src/components/DataTable/components/EmptyState.tsx +10 -0
  331. package/src/components/DataTable/components/FilterRow.tsx +12 -0
  332. package/src/components/DataTable/components/GroupHeader.tsx +12 -0
  333. package/src/components/DataTable/components/GroupingDropdown.tsx +12 -0
  334. package/src/components/DataTable/components/ImportModal.tsx +7 -0
  335. package/src/components/DataTable/components/LoadingState.tsx +6 -0
  336. package/src/components/DataTable/components/PaginationControls.tsx +16 -1
  337. package/src/components/DataTable/components/RowComponent.tsx +391 -0
  338. package/src/components/DataTable/components/UnifiedTableBody.tsx +62 -852
  339. package/src/components/DataTable/components/VirtualizedDataTable.tsx +16 -4
  340. package/src/components/DataTable/components/__tests__/AccessDeniedPage.test.tsx +4 -2
  341. package/src/components/DataTable/components/__tests__/DataTableModals.test.tsx +23 -23
  342. package/src/components/DataTable/components/__tests__/EditableRow.test.tsx +11 -11
  343. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +36 -36
  344. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +27 -27
  345. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +39 -39
  346. package/src/components/DataTable/components/__tests__/UnifiedTableBody.test.tsx +33 -33
  347. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +29 -29
  348. package/src/components/DataTable/components/cellValueUtils.ts +40 -0
  349. package/src/components/DataTable/components/hooks/useImportModalFocus.ts +53 -0
  350. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +126 -0
  351. package/src/components/DataTable/context/DataTableContext.tsx +50 -0
  352. package/src/components/DataTable/core/ColumnFactory.ts +31 -0
  353. package/src/components/DataTable/core/DataTableContext.tsx +32 -1
  354. package/src/components/DataTable/hooks/useColumnOrderPersistence.ts +10 -0
  355. package/src/components/DataTable/hooks/useColumnReordering.ts +14 -2
  356. package/src/components/DataTable/hooks/useColumnVisibilityPersistence.ts +10 -0
  357. package/src/components/DataTable/hooks/useDataTableDataPipeline.ts +16 -0
  358. package/src/components/DataTable/hooks/useDataTablePermissions.ts +124 -32
  359. package/src/components/DataTable/hooks/useDataTableState.ts +35 -1
  360. package/src/components/DataTable/hooks/useEffectiveColumnOrder.ts +12 -0
  361. package/src/components/DataTable/hooks/useKeyboardNavigation.ts +2 -2
  362. package/src/components/DataTable/hooks/useServerSideDataEffect.ts +11 -0
  363. package/src/components/DataTable/hooks/useTableColumns.ts +8 -0
  364. package/src/components/DataTable/hooks/useTableHandlers.ts +14 -0
  365. package/src/components/DataTable/styles.ts +6 -6
  366. package/src/components/DataTable/types.ts +6 -10
  367. package/src/components/DataTable/utils/a11yUtils.ts +7 -0
  368. package/src/components/DataTable/utils/debugTools.ts +18 -113
  369. package/src/components/DataTable/utils/errorHandling.ts +12 -0
  370. package/src/components/DataTable/utils/exportUtils.ts +9 -0
  371. package/src/components/DataTable/utils/flexibleImport.ts +12 -48
  372. package/src/components/DataTable/utils/paginationUtils.ts +8 -0
  373. package/src/components/DataTable/utils/performanceUtils.ts +5 -1
  374. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +8 -14
  375. package/src/components/Dialog/Dialog.tsx +8 -7
  376. package/src/components/ErrorBoundary/ErrorBoundary.test.tsx +180 -1
  377. package/src/components/ErrorBoundary/ErrorBoundary.tsx +46 -6
  378. package/src/components/ErrorBoundary/ErrorBoundaryContext.tsx +129 -0
  379. package/src/components/ErrorBoundary/index.ts +27 -2
  380. package/src/components/EventSelector/EventSelector.tsx +4 -1
  381. package/src/components/FileDisplay/FileDisplay.test.tsx +2 -2
  382. package/src/components/FileDisplay/FileDisplay.tsx +32 -18
  383. package/src/components/FileUpload/FileUpload.tsx +22 -2
  384. package/src/components/Footer/Footer.test.tsx +16 -16
  385. package/src/components/Footer/Footer.tsx +15 -12
  386. package/src/components/Form/Form.test.tsx +36 -15
  387. package/src/components/Form/Form.tsx +31 -26
  388. package/src/components/Header/Header.tsx +22 -11
  389. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +40 -40
  390. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +1 -1
  391. package/src/components/Input/Input.test.tsx +2 -2
  392. package/src/components/Input/Input.tsx +36 -34
  393. package/src/components/Label/Label.tsx +1 -1
  394. package/src/components/LoadingSpinner/LoadingSpinner.test.tsx +4 -4
  395. package/src/components/LoadingSpinner/LoadingSpinner.tsx +1 -1
  396. package/src/components/LoginForm/LoginForm.test.tsx +42 -42
  397. package/src/components/LoginForm/LoginForm.tsx +12 -8
  398. package/src/components/NavigationMenu/NavigationMenu.tsx +15 -514
  399. package/src/components/NavigationMenu/types.ts +56 -0
  400. package/src/components/NavigationMenu/useNavigationFiltering.ts +390 -0
  401. package/src/components/OrganisationSelector/OrganisationSelector.tsx +3 -0
  402. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +1 -1
  403. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +54 -52
  404. package/src/components/PaceAppLayout/PaceAppLayout.tsx +33 -12
  405. package/src/components/PaceAppLayout/README.md +1 -1
  406. package/src/components/PaceAppLayout/test-setup.tsx +1 -2
  407. package/src/components/PaceLoginPage/PaceLoginPage.tsx +4 -1
  408. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +33 -33
  409. package/src/components/PasswordChange/PasswordChangeForm.tsx +10 -1
  410. package/src/components/Progress/Progress.tsx +1 -1
  411. package/src/components/ProtectedRoute/ProtectedRoute.tsx +3 -9
  412. package/src/components/PublicLayout/PublicPageLayout.tsx +3 -6
  413. package/src/components/PublicLayout/PublicPageProvider.tsx +4 -0
  414. package/src/components/Select/Select.tsx +95 -438
  415. package/src/components/Select/context.ts +23 -0
  416. package/src/components/Select/hooks/useSelectEvents.ts +87 -0
  417. package/src/components/Select/hooks/useSelectSearch.ts +91 -0
  418. package/src/components/Select/hooks/useSelectState.ts +104 -0
  419. package/src/components/Select/index.ts +9 -1
  420. package/src/components/Select/types.ts +123 -0
  421. package/src/components/Select/utils/text.ts +26 -0
  422. package/src/components/SessionRestorationLoader/SessionRestorationLoader.tsx +5 -6
  423. package/src/components/Switch/Switch.tsx +4 -4
  424. package/src/components/Table/Table.tsx +1 -1
  425. package/src/components/Tabs/Tabs.tsx +1 -1
  426. package/src/components/Textarea/Textarea.tsx +27 -29
  427. package/src/components/Toast/Toast.tsx +5 -1
  428. package/src/components/Tooltip/Tooltip.tsx +3 -3
  429. package/src/components/UserMenu/UserMenu.test.tsx +24 -11
  430. package/src/components/UserMenu/UserMenu.tsx +22 -19
  431. package/src/components/index.ts +2 -2
  432. package/src/hooks/__tests__/hooks.integration.test.tsx +80 -55
  433. package/src/hooks/__tests__/index.unit.test.ts +2 -5
  434. package/src/hooks/__tests__/useStorage.unit.test.ts +36 -36
  435. package/src/hooks/index.ts +1 -2
  436. package/src/hooks/public/usePublicEvent.ts +5 -1
  437. package/src/hooks/public/usePublicEventLogo.ts +5 -1
  438. package/src/hooks/public/usePublicFileDisplay.ts +4 -0
  439. package/src/hooks/public/usePublicRouteParams.ts +5 -1
  440. package/src/hooks/services/useAuth.ts +32 -0
  441. package/src/hooks/services/useCurrentEvent.ts +6 -0
  442. package/src/hooks/services/useCurrentOrganisation.ts +6 -0
  443. package/src/hooks/useDataTableState.ts +8 -18
  444. package/src/hooks/useDebounce.ts +9 -0
  445. package/src/hooks/useEventTheme.ts +6 -0
  446. package/src/hooks/useFileDisplay.ts +4 -0
  447. package/src/hooks/useFileReference.ts +25 -7
  448. package/src/hooks/useFileUrl.ts +11 -1
  449. package/src/hooks/useFocusManagement.ts +16 -2
  450. package/src/hooks/useFocusTrap.ts +7 -4
  451. package/src/hooks/useFormDialog.ts +8 -7
  452. package/src/hooks/useInactivityTracker.ts +4 -1
  453. package/src/hooks/useKeyboardShortcuts.ts +4 -0
  454. package/src/hooks/useOrganisationPermissions.ts +4 -0
  455. package/src/hooks/useOrganisationSecurity.ts +4 -0
  456. package/src/hooks/usePerformanceMonitor.ts +4 -0
  457. package/src/hooks/usePermissionCache.ts +8 -1
  458. package/src/hooks/useQueryCache.ts +12 -1
  459. package/src/hooks/useSessionRestoration.ts +4 -0
  460. package/src/hooks/useStorage.ts +4 -0
  461. package/src/hooks/useToast.ts +3 -3
  462. package/src/index.ts +2 -1
  463. package/src/providers/__tests__/OrganisationProvider.test.tsx +115 -49
  464. package/src/providers/__tests__/ProviderLifecycle.test.tsx +21 -6
  465. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +10 -10
  466. package/src/providers/services/AuthServiceProvider.tsx +18 -0
  467. package/src/providers/services/EventServiceProvider.tsx +18 -0
  468. package/src/providers/services/InactivityServiceProvider.tsx +18 -0
  469. package/src/providers/services/OrganisationServiceProvider.tsx +18 -0
  470. package/src/providers/services/UnifiedAuthProvider.tsx +58 -22
  471. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +33 -7
  472. package/src/rbac/README.md +1 -1
  473. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +26 -26
  474. package/src/rbac/__tests__/scenarios.user-role.test.tsx +4 -5
  475. package/src/rbac/adapters.tsx +14 -5
  476. package/src/rbac/api.ts +100 -67
  477. package/src/rbac/components/EnhancedNavigationMenu.tsx +1 -1
  478. package/src/rbac/components/NavigationGuard.tsx +1 -1
  479. package/src/rbac/components/NavigationProvider.tsx +5 -2
  480. package/src/rbac/components/PagePermissionGuard.tsx +158 -18
  481. package/src/rbac/components/PagePermissionProvider.tsx +1 -1
  482. package/src/rbac/components/PermissionEnforcer.tsx +1 -1
  483. package/src/rbac/components/RoleBasedRouter.tsx +6 -2
  484. package/src/rbac/components/SecureDataProvider.test.tsx +84 -49
  485. package/src/rbac/components/SecureDataProvider.tsx +21 -6
  486. package/src/rbac/components/__tests__/PagePermissionGuard.race-condition.test.tsx +24 -14
  487. package/src/rbac/components/__tests__/PagePermissionGuard.test.tsx +7 -0
  488. package/src/rbac/components/__tests__/PagePermissionGuard.verification.test.tsx +14 -6
  489. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +15 -4
  490. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +148 -24
  491. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +81 -15
  492. package/src/rbac/engine.ts +38 -14
  493. package/src/rbac/hooks/permissions/index.ts +7 -0
  494. package/src/rbac/hooks/permissions/useAccessLevel.ts +105 -0
  495. package/src/rbac/hooks/permissions/useCachedPermissions.ts +79 -0
  496. package/src/rbac/hooks/permissions/useCan.ts +347 -0
  497. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +90 -0
  498. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +90 -0
  499. package/src/rbac/hooks/permissions/useMultiplePermissions.ts +93 -0
  500. package/src/rbac/hooks/permissions/usePermissions.ts +253 -0
  501. package/src/rbac/hooks/useCan.test.ts +71 -64
  502. package/src/rbac/hooks/usePermissions.ts +14 -995
  503. package/src/rbac/hooks/useResourcePermissions.test.ts +54 -18
  504. package/src/rbac/hooks/useResourcePermissions.ts +14 -4
  505. package/src/rbac/hooks/useSecureSupabase.ts +33 -13
  506. package/src/rbac/permissions.ts +0 -30
  507. package/src/rbac/secureClient.ts +212 -61
  508. package/src/rbac/types.ts +8 -0
  509. package/src/theming/__tests__/parseEventColours.test.ts +6 -9
  510. package/src/theming/parseEventColours.ts +5 -19
  511. package/src/types/vitest-globals.d.ts +51 -26
  512. package/src/utils/__mocks__/supabaseMock.ts +1 -3
  513. package/src/utils/__tests__/formatting.unit.test.ts +4 -4
  514. package/src/utils/__tests__/index.unit.test.ts +2 -2
  515. package/src/utils/audit/audit.ts +0 -3
  516. package/src/utils/core/cn.ts +1 -1
  517. package/src/utils/file-reference/index.ts +53 -1
  518. package/src/utils/formatting/formatting.ts +8 -18
  519. package/src/utils/index.ts +0 -1
  520. package/src/utils/security/secureDataAccess.test.ts +31 -20
  521. package/src/utils/security/secureDataAccess.ts +4 -3
  522. package/dist/chunk-6C4YBBJM.js +0 -628
  523. package/dist/chunk-6C4YBBJM.js.map +0 -1
  524. package/dist/chunk-7D4SUZUM.js 2.map +0 -1
  525. package/dist/chunk-7EQTDTTJ.js 2.map +0 -1
  526. package/dist/chunk-7EQTDTTJ.js.map +0 -1
  527. package/dist/chunk-7FLMSG37.js 2.map +0 -1
  528. package/dist/chunk-7FLMSG37.js.map +0 -1
  529. package/dist/chunk-BC4IJKSL.js.map +0 -1
  530. package/dist/chunk-E3SPN4VZ.js +0 -12917
  531. package/dist/chunk-E3SPN4VZ.js.map +0 -1
  532. package/dist/chunk-E66EQZE6 5.js +0 -37
  533. package/dist/chunk-E66EQZE6.js 2.map +0 -1
  534. package/dist/chunk-HWIIPPNI.js.map +0 -1
  535. package/dist/chunk-I7PSE6JW 5.js +0 -191
  536. package/dist/chunk-I7PSE6JW.js 2.map +0 -1
  537. package/dist/chunk-I7PSE6JW.js.map +0 -1
  538. package/dist/chunk-IIELH4DL.js.map +0 -1
  539. package/dist/chunk-KNC55RTG.js 5.map +0 -1
  540. package/dist/chunk-KNC55RTG.js.map +0 -1
  541. package/dist/chunk-KQCRWDSA.js 5.map +0 -1
  542. package/dist/chunk-LFNCN2SP.js +0 -412
  543. package/dist/chunk-LFNCN2SP.js 2.map +0 -1
  544. package/dist/chunk-LFNCN2SP.js.map +0 -1
  545. package/dist/chunk-LMC26NLJ 2.js +0 -84
  546. package/dist/chunk-NOAYCWCX.js +0 -4993
  547. package/dist/chunk-NOAYCWCX.js.map +0 -1
  548. package/dist/chunk-QWWZ5CAQ.js 3.map +0 -1
  549. package/dist/chunk-QWWZ5CAQ.js.map +0 -1
  550. package/dist/chunk-QXHPKYJV 3.js +0 -113
  551. package/dist/chunk-R77UEZ4E.js +0 -68
  552. package/dist/chunk-R77UEZ4E.js.map +0 -1
  553. package/dist/chunk-SQGMNID3.js.map +0 -1
  554. package/dist/chunk-VBXEHIUJ.js 6.map +0 -1
  555. package/dist/chunk-XNXXZ43G.js.map +0 -1
  556. package/dist/chunk-ZSAAAMVR 6.js +0 -25
  557. package/dist/components.js 5.map +0 -1
  558. package/dist/styles/index 2.js +0 -12
  559. package/dist/styles/index.js 5.map +0 -1
  560. package/dist/theming/runtime 5.js +0 -19
  561. package/dist/theming/runtime.js 5.map +0 -1
  562. package/docs/api/classes/ErrorBoundary.md +0 -144
  563. package/docs/migration/quick-migration-guide.md +0 -356
  564. package/docs/migration/service-architecture.md +0 -281
  565. package/src/hooks/__tests__/useSecureDataAccess.unit.test.tsx +0 -680
  566. package/src/hooks/useSecureDataAccess.test.ts +0 -559
  567. package/src/hooks/useSecureDataAccess.ts +0 -666
  568. /package/dist/{DataTable-5FU7IESH.js.map → DataTable-TPTKCX4D.js.map} +0 -0
  569. /package/dist/{UnifiedAuthProvider-RGJTDE2C.js.map → UnifiedAuthProvider-CH6Z342H.js.map} +0 -0
  570. /package/dist/{api-N774RPUA.js.map → api-MVVQZLJI.js.map} +0 -0
  571. /package/docs/migration/{organisation-context-timing-fix.md → V0.3.44_organisation-context-timing-fix.md} +0 -0
  572. /package/docs/migration/{rbac-migration.md → V0.4.0_rbac-migration.md} +0 -0
  573. /package/docs/migration/{person-scoped-profiles-migration-guide.md → V0.5.190_person-scoped-profiles-migration-guide.md} +0 -0
  574. /package/examples/{rbac → RBAC}/CompleteRBACExample.tsx +0 -0
  575. /package/examples/{rbac → RBAC}/EventBasedApp.tsx +0 -0
  576. /package/examples/{rbac → RBAC}/PermissionExample.tsx +0 -0
  577. /package/examples/{rbac → RBAC}/index.ts +0 -0
@@ -1,666 +0,0 @@
1
- /**
2
- * @file useSecureDataAccess Hook
3
- * @package @jmruthers/pace-core
4
- * @module Hooks/useSecureDataAccess
5
- * @since 0.4.0
6
- *
7
- * Hook for secure database operations with mandatory organisation context.
8
- * Ensures all data access is properly scoped to the user's current organisation.
9
- *
10
- * @example
11
- * ```tsx
12
- * function DataComponent() {
13
- * const { secureQuery, secureInsert, secureUpdate, secureDelete } = useSecureDataAccess();
14
- *
15
- * const loadData = async () => {
16
- * try {
17
- * // Automatically includes organisation_id filter
18
- * const events = await secureQuery('core_events', '*', { is_visible: true });
19
- * console.log('Organisation events:', events);
20
- * } catch (error) {
21
- * console.error('Failed to load data:', error);
22
- * }
23
- * };
24
- *
25
- * const createEvent = async (eventData) => {
26
- * try {
27
- * // Automatically sets organisation_id
28
- * const newEvent = await secureInsert('core_events', eventData);
29
- * console.log('Created event:', newEvent);
30
- * } catch (error) {
31
- * console.error('Failed to create event:', error);
32
- * }
33
- * };
34
- *
35
- * return (
36
- * <div>
37
- * <button onClick={loadData}>Load Data</button>
38
- * <button onClick={() => createEvent({ event_name: 'New Event' })}>
39
- * Create Event
40
- * </button>
41
- * </div>
42
- * );
43
- * }
44
- * ```
45
- *
46
- * @security
47
- * - All queries automatically include organisation_id filter
48
- * - Validates organisation context before any operation
49
- * - Prevents data leaks between organisations
50
- * - Error handling for security violations
51
- * - Type-safe database operations
52
- */
53
-
54
- import { useCallback, useState, useContext } from 'react';
55
- import { useUnifiedAuth } from '../providers';
56
- import { useOrganisations } from './useOrganisations';
57
- import { EventServiceContext } from '../providers/services/EventServiceProvider';
58
- import { setOrganisationContext } from '../utils/context/organisationContext';
59
- import { logger } from '../utils/core/logger';
60
- import type { Permission } from '../rbac/types';
61
- import type { OrganisationSecurityError } from '../types/organisation';
62
- import { useOrganisationSecurity } from './useOrganisationSecurity';
63
- import { useResolvedScope } from '../rbac/hooks/useResolvedScope';
64
-
65
- export interface SecureDataAccessReturn {
66
- /** Execute a secure query with organisation filtering */
67
- secureQuery: <T = any>(
68
- table: string,
69
- columns: string,
70
- filters?: Record<string, any>,
71
- options?: {
72
- orderBy?: string;
73
- ascending?: boolean;
74
- limit?: number;
75
- offset?: number;
76
- }
77
- ) => Promise<T[]>;
78
-
79
- /** Execute a secure insert with organisation context */
80
- secureInsert: <T = any>(
81
- table: string,
82
- data: Record<string, any>
83
- ) => Promise<T>;
84
-
85
- /** Execute a secure update with organisation filtering */
86
- secureUpdate: <T = any>(
87
- table: string,
88
- data: Record<string, any>,
89
- filters: Record<string, any>
90
- ) => Promise<T[]>;
91
-
92
- /** Execute a secure delete with organisation filtering */
93
- secureDelete: (
94
- table: string,
95
- filters: Record<string, any>
96
- ) => Promise<void>;
97
-
98
- /** Execute a secure RPC call with organisation context */
99
- secureRpc: <T = any>(
100
- functionName: string,
101
- params?: Record<string, any>
102
- ) => Promise<T>;
103
-
104
- /** Get current organisation ID */
105
- getCurrentOrganisationId: () => string;
106
-
107
- /** Validate organisation context */
108
- validateContext: () => void;
109
-
110
- // NEW: Phase 1 - Enhanced Security Features
111
- /** Check if data access is allowed for a table and operation */
112
- isDataAccessAllowed: (table: string, operation: string) => boolean;
113
-
114
- /** Get all data access permissions for current user */
115
- getDataAccessPermissions: () => Record<string, string[]>;
116
-
117
- /** Check if strict mode is enabled */
118
- isStrictMode: boolean;
119
-
120
- /** Check if audit logging is enabled */
121
- isAuditLogEnabled: boolean;
122
-
123
- /** Get data access history */
124
- getDataAccessHistory: () => DataAccessRecord[];
125
-
126
- /** Clear data access history */
127
- clearDataAccessHistory: () => void;
128
-
129
- /** Validate data access attempt */
130
- validateDataAccess: (table: string, operation: string) => boolean;
131
- }
132
-
133
- export interface DataAccessRecord {
134
- table: string;
135
- operation: string;
136
- userId: string;
137
- organisationId: string;
138
- allowed: boolean;
139
- timestamp: string;
140
- query?: string;
141
- filters?: Record<string, any>;
142
- }
143
-
144
- /**
145
- * Hook for secure data access with automatic organisation filtering
146
- *
147
- * All database operations automatically include organisation context:
148
- * - Queries filter by organisation_id
149
- * - Inserts include organisation_id
150
- * - Updates/deletes are scoped to organisation
151
- * - RPC calls include organisation_id parameter
152
- */
153
- export function useSecureDataAccess(): SecureDataAccessReturn {
154
- const { supabase, user, session, selectedOrganisation, selectedEvent } = useUnifiedAuth();
155
-
156
- // Get selected event for event-scoped RPC calls
157
- // Use useContext directly to safely check if EventServiceProvider is available
158
- const eventServiceContext = useContext(EventServiceContext);
159
- const eventFromContext = eventServiceContext?.eventService?.getSelectedEvent() || null;
160
- const effectiveSelectedEvent = selectedEvent || eventFromContext;
161
- const { superAdminContext } = useOrganisationSecurity();
162
- const isSuperAdmin = superAdminContext.isSuperAdmin;
163
-
164
- // Use resolved scope to get organisationId (derived from event if needed)
165
- const { resolvedScope } = useResolvedScope({
166
- supabase,
167
- selectedOrganisationId: selectedOrganisation?.id || null,
168
- selectedEventId: effectiveSelectedEvent?.event_id || null
169
- });
170
-
171
- const validateContext = useCallback((): void => {
172
- if (!supabase) {
173
- throw new Error('No Supabase client available') as OrganisationSecurityError;
174
- }
175
- if (!user || !session) {
176
- throw new Error('User must be authenticated with valid session') as OrganisationSecurityError;
177
- }
178
-
179
- if (isSuperAdmin) {
180
- return;
181
- }
182
-
183
- if (!resolvedScope?.organisationId) {
184
- throw new Error('Organisation context is required for data access') as OrganisationSecurityError;
185
- }
186
- }, [supabase, user, session, resolvedScope, isSuperAdmin]);
187
-
188
- const getCurrentOrganisationId = useCallback((): string => {
189
- if (isSuperAdmin) {
190
- // For super admins, try to get org from resolved scope or selectedOrganisation
191
- return resolvedScope?.organisationId || selectedOrganisation?.id || '';
192
- }
193
-
194
- validateContext();
195
- return resolvedScope?.organisationId || '';
196
- }, [validateContext, resolvedScope, selectedOrganisation, isSuperAdmin]);
197
-
198
- // Set organisation context in database session
199
- const setOrganisationContextInSession = useCallback(async (organisationId?: string): Promise<void> => {
200
- if (!supabase || !organisationId) {
201
- return;
202
- }
203
-
204
- await setOrganisationContext(supabase, organisationId);
205
- }, [supabase]);
206
-
207
- const secureQuery = useCallback(async <T = any>(
208
- table: string,
209
- columns: string,
210
- filters: Record<string, any> = {},
211
- options: {
212
- orderBy?: string;
213
- ascending?: boolean;
214
- limit?: number;
215
- offset?: number;
216
- } = {}
217
- ): Promise<T[]> => {
218
- validateContext();
219
- const bypassOrganisationFilter = isSuperAdmin;
220
- const organisationId = bypassOrganisationFilter ? undefined : getCurrentOrganisationId();
221
-
222
- // Set organisation context in database session
223
- await setOrganisationContextInSession(organisationId);
224
-
225
- // Build query with organisation filter
226
- let query = supabase!
227
- .from(table)
228
- .select(columns);
229
-
230
- // Add organisation filter only if table has organisation_id column
231
- // Defense in depth strategy:
232
- // - RLS policies are the primary security layer (cannot be bypassed)
233
- // - Application-level filtering adds an additional layer of protection
234
- const tablesWithOrganisation = [
235
- 'core_events', 'organisation_settings',
236
- 'rbac_event_app_roles', 'rbac_organisation_roles',
237
- // SECURITY: Phase 2 additions - complete organisation table mapping
238
- 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',
239
- // SECURITY: Emergency additions for Phase 1 fixes
240
- 'cake_meal', 'cake_mealtype', 'core_person',
241
- // NOTE: core_member, medi_profile, core_contact, core_consent, core_identification, core_qualification
242
- // are now person-scoped (not organisation-scoped) - removed from this list
243
- // SECURITY: Phase 3A additions - medical and personal data
244
- // NOTE: medi_condition, medi_diet, medi_action_plan, medi_profile_versions are now person-scoped
245
- // (via medi_profile) - removed from this list
246
- // core_identification_type remains organisation-scoped (lookup table)
247
- 'core_identification_type',
248
- 'form_responses', 'form_response_values', 'forms',
249
- // SECURITY: Phase 3B additions - remaining critical tables
250
- 'invoice', 'line_item', 'credit_balance', 'payment_method',
251
- 'form_contexts', 'form_field_config', 'form_fields',
252
- 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item',
253
- 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier',
254
- 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions',
255
- // rbac_user_profiles has organisation_id but uses conditional filtering
256
- 'rbac_user_profiles'
257
- ];
258
-
259
- // Apply organisation filtering based on table and super admin status
260
- if (!bypassOrganisationFilter && organisationId && tablesWithOrganisation.includes(table)) {
261
- // For rbac_user_profiles: Super admins see all (no filter), non-super-admins get filtered (defense in depth)
262
- // For other tables: Always apply filter
263
- if (table === 'rbac_user_profiles' && isSuperAdmin) {
264
- // Super admin: No org filter - RLS handles access control
265
- // This allows super admins to see all users across all organisations
266
- } else {
267
- // Non-super-admin OR other tables: Apply org filter as defense in depth
268
- query = query.eq('organisation_id', organisationId);
269
- }
270
- }
271
-
272
- // Apply additional filters
273
- Object.entries(filters).forEach(([key, value]) => {
274
- if (value !== undefined && value !== null) {
275
- // Handle qualified column names (e.g., 'users.role')
276
- const columnName = key.includes('.') ? key.split('.').pop()! : key;
277
- query = query.eq(columnName, value);
278
- }
279
- });
280
-
281
- // Apply options
282
- if (options.orderBy) {
283
- // Only use the column name, not a qualified name
284
- const orderByColumn = options.orderBy.split('.').pop();
285
- if (orderByColumn) {
286
- query = query.order(orderByColumn, { ascending: options.ascending ?? true });
287
- }
288
- }
289
-
290
- if (options.limit) {
291
- query = query.limit(options.limit);
292
- }
293
-
294
- if (options.offset) {
295
- query = query.range(options.offset, options.offset + (options.limit || 100) - 1);
296
- }
297
-
298
- const { data, error } = await query;
299
-
300
- if (error) {
301
- logger.error('useSecureDataAccess', 'Query failed', { table, columns, filters, error });
302
- // NEW: Phase 1 - Record failed data access attempt
303
- recordDataAccess(table, 'read', false, `SELECT ${columns} FROM ${table}`, filters);
304
- throw error;
305
- }
306
-
307
- // NEW: Phase 1 - Record successful data access attempt
308
- recordDataAccess(table, 'read', true, `SELECT ${columns} FROM ${table}`, filters);
309
-
310
- return (data as T[]) || [];
311
- }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase, isSuperAdmin]);
312
-
313
- const secureInsert = useCallback(async <T = any>(
314
- table: string,
315
- data: Record<string, any>
316
- ): Promise<T> => {
317
- validateContext();
318
- const bypassOrganisationFilter = isSuperAdmin;
319
- const organisationId = bypassOrganisationFilter ? undefined : getCurrentOrganisationId();
320
-
321
- // Set organisation context in database session
322
- await setOrganisationContextInSession(organisationId);
323
-
324
- // Ensure organisation_id is set
325
- const secureData = bypassOrganisationFilter
326
- ? { ...data }
327
- : {
328
- ...data,
329
- organisation_id: organisationId
330
- };
331
-
332
- const { data: insertData, error } = await supabase!
333
- .from(table)
334
- .insert(secureData)
335
- .select()
336
- .single();
337
-
338
- if (error) {
339
- logger.error('useSecureDataAccess', 'Insert failed', { table, data: secureData, error });
340
- throw error;
341
- }
342
-
343
- return insertData as T;
344
- }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase, isSuperAdmin]);
345
-
346
- const secureUpdate = useCallback(async <T = any>(
347
- table: string,
348
- data: Record<string, any>,
349
- filters: Record<string, any>
350
- ): Promise<T[]> => {
351
- validateContext();
352
- const bypassOrganisationFilter = isSuperAdmin;
353
- const organisationId = bypassOrganisationFilter ? undefined : getCurrentOrganisationId();
354
-
355
- // Set organisation context in database session
356
- await setOrganisationContextInSession(organisationId);
357
-
358
- // Filter out organisation_id from data to prevent manipulation
359
- const { organisation_id, ...secureData } = data;
360
-
361
- // Build update query with organisation filter
362
- let query = supabase!
363
- .from(table)
364
- .update(secureData);
365
-
366
- // Add organisation filter only if table has organisation_id column
367
- const tablesWithOrganisation = [
368
- 'core_events', 'organisation_settings',
369
- 'rbac_event_app_roles', 'rbac_organisation_roles',
370
- // SECURITY: Phase 2 additions - complete organisation table mapping
371
- 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',
372
- // SECURITY: Emergency additions for Phase 1 fixes
373
- 'cake_meal', 'cake_mealtype', 'core_person', 'core_member'
374
- ];
375
-
376
- if (!bypassOrganisationFilter && organisationId && tablesWithOrganisation.includes(table)) {
377
- query = query.eq('organisation_id', organisationId);
378
- }
379
-
380
- // Apply filters
381
- Object.entries(filters).forEach(([key, value]) => {
382
- if (value !== undefined && value !== null) {
383
- query = query.eq(key, value);
384
- }
385
- });
386
-
387
- const { data: updateData, error } = await query.select();
388
-
389
- if (error) {
390
- logger.error('useSecureDataAccess', 'Update failed', { table, data: secureData, filters, error });
391
- throw error;
392
- }
393
-
394
- return (updateData as T[]) || [];
395
- }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase, isSuperAdmin]);
396
-
397
- const secureDelete = useCallback(async (
398
- table: string,
399
- filters: Record<string, any>
400
- ): Promise<void> => {
401
- validateContext();
402
- const bypassOrganisationFilter = isSuperAdmin;
403
- const organisationId = bypassOrganisationFilter ? undefined : getCurrentOrganisationId();
404
-
405
- // Set organisation context in database session
406
- await setOrganisationContextInSession(organisationId);
407
-
408
- // Build delete query with organisation filter
409
- let query = supabase!
410
- .from(table)
411
- .delete();
412
-
413
- // Add organisation filter only if table has organisation_id column
414
- const tablesWithOrganisation = [
415
- 'core_events', 'organisation_settings',
416
- 'rbac_event_app_roles', 'rbac_organisation_roles',
417
- // SECURITY: Phase 2 additions - complete organisation table mapping
418
- 'organisation_audit_log', 'organisation_invitations', 'organisation_app_access',
419
- // SECURITY: Emergency additions for Phase 1 fixes
420
- 'cake_meal', 'cake_mealtype', 'core_person', 'core_member',
421
- // SECURITY: Phase 3A additions - medical and personal data
422
- 'medi_profile', 'medi_condition', 'medi_diet', 'medi_action_plan', 'medi_profile_versions',
423
- 'core_consent', 'core_contact', 'core_identification', 'core_identification_type', 'core_qualification',
424
- 'form_responses', 'form_response_values', 'forms',
425
- // SECURITY: Phase 3B additions - remaining critical tables
426
- 'invoice', 'line_item', 'credit_balance', 'payment_method',
427
- 'form_contexts', 'form_field_config', 'form_fields',
428
- 'cake_delivery', 'cake_diettype', 'cake_diner', 'cake_dish', 'cake_item',
429
- 'cake_logistics', 'cake_mealplan', 'cake_package', 'cake_recipe', 'cake_supplier',
430
- 'cake_supply', 'cake_unit', 'event_app_access', 'base_application', 'base_questions'
431
- ];
432
-
433
- if (!bypassOrganisationFilter && organisationId && tablesWithOrganisation.includes(table)) {
434
- query = query.eq('organisation_id', organisationId);
435
- }
436
-
437
- // Apply filters
438
- Object.entries(filters).forEach(([key, value]) => {
439
- if (value !== undefined && value !== null) {
440
- query = query.eq(key, value);
441
- }
442
- });
443
-
444
- const { error } = await query;
445
-
446
- if (error) {
447
- logger.error('useSecureDataAccess', 'Delete failed', { table, filters, error });
448
- throw error;
449
- }
450
- }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase, isSuperAdmin]);
451
-
452
- const secureRpc = useCallback(async <T = any>(
453
- functionName: string,
454
- params: Record<string, any> = {}
455
- ): Promise<T> => {
456
- validateContext();
457
- const bypassOrganisationFilter = isSuperAdmin;
458
- const organisationId = bypassOrganisationFilter ? undefined : getCurrentOrganisationId();
459
-
460
- // Set organisation context in database session
461
- await setOrganisationContextInSession(organisationId);
462
-
463
- // Include organisation_id in RPC parameters
464
- // Some functions use p_organisation_id instead of organisation_id (to avoid conflicts with RETURNS TABLE columns)
465
- const functionsWithPOrganisationId = [
466
- 'data_cake_diners_list',
467
- 'data_cake_mealplans_list'
468
- ];
469
-
470
- const paramName = functionsWithPOrganisationId.includes(functionName)
471
- ? 'p_organisation_id'
472
- : 'organisation_id';
473
-
474
- // Functions that need p_event_id for event-app role permission checks
475
- // Note: Even org-scoped functions (like items, packages, suppliers) need event_id
476
- // for permission checks when users have event-app roles
477
- const functionsNeedingEventId = [
478
- 'data_cake_items_list',
479
- 'data_cake_packages_list',
480
- 'data_cake_suppliers_list',
481
- 'data_cake_diettypes_list',
482
- 'data_cake_mealtypes_list',
483
- 'data_cake_diners_list',
484
- 'data_cake_mealplans_list',
485
- 'data_cake_dishes_list',
486
- 'data_cake_recipes_list',
487
- 'data_cake_meals_list',
488
- 'data_cake_units_list',
489
- 'data_cake_orders_list',
490
- 'app_cake_item_create',
491
- 'app_cake_item_update',
492
- 'app_cake_package_create',
493
- 'app_cake_package_update',
494
- 'app_cake_supplier_create',
495
- 'app_cake_supplier_update',
496
- 'app_cake_supplier_delete',
497
- 'app_cake_meal_create',
498
- 'app_cake_meal_update',
499
- 'app_cake_meal_delete',
500
- 'app_cake_unit_create',
501
- 'app_cake_unit_update',
502
- 'app_cake_unit_delete',
503
- 'app_cake_delivery_upsert'
504
- ];
505
-
506
- // Build secureParams with correct parameter order
507
- // For functions that require p_event_id as first parameter, ensure it's first
508
- const secureParams: Record<string, any> = {};
509
-
510
- // Functions where p_event_id is the FIRST required parameter (no default)
511
- const functionsWithEventIdFirst = [
512
- 'data_cake_meals_list',
513
- 'data_cake_units_list'
514
- ];
515
-
516
- // Add p_user_id explicitly for functions that need it (even though it has a default)
517
- // This ensures parameter matching works correctly
518
- if (user?.id) {
519
- secureParams.p_user_id = user.id;
520
- }
521
-
522
- // Add organisation_id parameter when needed
523
- if (!bypassOrganisationFilter && organisationId) {
524
- secureParams[paramName] = organisationId;
525
- } else if (organisationId && !(paramName in params)) {
526
- // Default to the current organisation if caller didn't specify one
527
- secureParams[paramName] = organisationId;
528
- }
529
-
530
- // Add p_event_id if function needs it and event is selected
531
- // CRITICAL: This must be added AFTER organisation_id but BEFORE caller params
532
- // to ensure it's not overwritten. For data_cake_items_list, p_event_id is the 3rd param.
533
- if (functionsNeedingEventId.includes(functionName) && selectedEvent?.event_id) {
534
- secureParams.p_event_id = selectedEvent.event_id;
535
- }
536
-
537
- // Add any other params passed by caller (limit, offset, etc.)
538
- // NOTE: This will NOT overwrite p_event_id if caller passes it, but we want to ensure
539
- // our value takes precedence if event is selected
540
- Object.assign(secureParams, params);
541
-
542
- // Ensure p_event_id is set if needed (after Object.assign, so it overrides caller params)
543
- if (functionsNeedingEventId.includes(functionName) && selectedEvent?.event_id) {
544
- secureParams.p_event_id = selectedEvent.event_id;
545
- }
546
-
547
- const { data, error } = await supabase!.rpc(functionName, secureParams);
548
-
549
- if (error) {
550
- logger.error('useSecureDataAccess', 'RPC failed', { functionName, params: secureParams, error });
551
- throw error;
552
- }
553
-
554
- return data as T;
555
- }, [validateContext, getCurrentOrganisationId, setOrganisationContextInSession, supabase, selectedEvent?.event_id, user?.id, isSuperAdmin]);
556
-
557
- // NEW: Phase 1 - Enhanced Security Features
558
- const [dataAccessHistory, setDataAccessHistory] = useState<DataAccessRecord[]>([]);
559
- const [isStrictMode] = useState(true); // Always enabled in Phase 1
560
- const [isAuditLogEnabled] = useState(true); // Always enabled in Phase 1
561
-
562
- // Check if data access is allowed for a table and operation
563
- const isDataAccessAllowed = useCallback((table: string, operation: string): boolean => {
564
- if (!user?.id) return false;
565
-
566
- // Use the existing RBAC system to check data access permissions
567
- // This is a synchronous check for the context - actual permission checking
568
- // happens in the secure data operations using the RBAC engine
569
- const permission = `${operation}:data.${table}` as Permission;
570
-
571
- // For now, we'll return true and let the secure data operations
572
- // handle the actual permission checking asynchronously
573
- // This context is mainly for tracking and audit purposes
574
- return true;
575
- }, [user?.id]);
576
-
577
- // Get all data access permissions for current user
578
- const getDataAccessPermissions = useCallback((): Record<string, string[]> => {
579
- if (!user?.id) return {};
580
-
581
- // For now, return empty object - this will be enhanced with actual permission checking
582
- // when we integrate with the existing RBAC system
583
- return {};
584
- }, [user?.id]);
585
-
586
- // Get data access history
587
- const getDataAccessHistory = useCallback((): DataAccessRecord[] => {
588
- return [...dataAccessHistory];
589
- }, [dataAccessHistory]);
590
-
591
- // Clear data access history
592
- const clearDataAccessHistory = useCallback(() => {
593
- setDataAccessHistory([]);
594
- }, []);
595
-
596
- // Validate data access attempt
597
- const validateDataAccess = useCallback((table: string, operation: string): boolean => {
598
- if (!user?.id) return false;
599
-
600
- // Validate organisation context
601
- try {
602
- validateContext();
603
- } catch (error) {
604
- logger.error('useSecureDataAccess', 'Organisation context validation failed', { table, operation, error });
605
- return false;
606
- }
607
-
608
- return isDataAccessAllowed(table, operation);
609
- }, [user?.id, validateContext, isDataAccessAllowed]);
610
-
611
- // Record data access attempt
612
- const recordDataAccess = useCallback((
613
- table: string,
614
- operation: string,
615
- allowed: boolean,
616
- query?: string,
617
- filters?: Record<string, any>
618
- ) => {
619
- if (!isAuditLogEnabled || !user?.id) return;
620
- const auditOrganisationId = getCurrentOrganisationId() || 'super-admin-bypass';
621
-
622
- const record: DataAccessRecord = {
623
- table,
624
- operation,
625
- userId: user.id,
626
- organisationId: auditOrganisationId,
627
- allowed,
628
- timestamp: new Date().toISOString(),
629
- query,
630
- filters
631
- };
632
-
633
- setDataAccessHistory(prev => {
634
- const newHistory = [record, ...prev];
635
- return newHistory.slice(0, 1000); // Keep last 1000 records
636
- });
637
-
638
- if (isStrictMode && !allowed) {
639
- logger.error('useSecureDataAccess', 'STRICT MODE VIOLATION: User attempted data access without permission', {
640
- table,
641
- operation,
642
- userId: user.id,
643
- organisationId: auditOrganisationId,
644
- timestamp: new Date().toISOString()
645
- });
646
- }
647
- }, [isAuditLogEnabled, isStrictMode, user?.id, getCurrentOrganisationId]);
648
-
649
- return {
650
- secureQuery,
651
- secureInsert,
652
- secureUpdate,
653
- secureDelete,
654
- secureRpc,
655
- getCurrentOrganisationId,
656
- validateContext,
657
- // NEW: Phase 1 - Enhanced Security Features
658
- isDataAccessAllowed,
659
- getDataAccessPermissions,
660
- isStrictMode,
661
- isAuditLogEnabled,
662
- getDataAccessHistory,
663
- clearDataAccessHistory,
664
- validateDataAccess
665
- };
666
- }
File without changes
File without changes
File without changes
File without changes