@jmruthers/pace-core 0.6.5 → 0.6.7

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 (473) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/audit-tool/00-dependencies.cjs +394 -0
  4. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  5. package/audit-tool/audits/02-project-structure.cjs +255 -0
  6. package/audit-tool/audits/03-architecture.cjs +196 -0
  7. package/audit-tool/audits/04-code-quality.cjs +149 -0
  8. package/audit-tool/audits/05-styling.cjs +224 -0
  9. package/audit-tool/audits/06-security-rbac.cjs +544 -0
  10. package/audit-tool/audits/07-api-tech-stack.cjs +301 -0
  11. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  12. package/audit-tool/audits/09-operations.cjs +208 -0
  13. package/audit-tool/index.cjs +291 -0
  14. package/audit-tool/utils/code-utils.cjs +218 -0
  15. package/audit-tool/utils/file-utils.cjs +230 -0
  16. package/audit-tool/utils/report-utils.cjs +241 -0
  17. package/core-usage-manifest.json +93 -0
  18. package/cursor-rules/00-standards-overview.mdc +156 -0
  19. package/cursor-rules/01-pace-core-compliance.mdc +586 -0
  20. package/cursor-rules/02-project-structure.mdc +42 -4
  21. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +126 -10
  22. package/cursor-rules/04-code-quality.mdc +419 -0
  23. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +104 -34
  24. package/cursor-rules/06-security-rbac.mdc +518 -0
  25. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  26. package/cursor-rules/08-testing-documentation.mdc +324 -0
  27. package/cursor-rules/09-operations.mdc +365 -0
  28. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  29. package/dist/DataTable-7PMH7XN7.js +15 -0
  30. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  31. package/dist/{PublicPageProvider-QTFVrL-Z.d.ts → PublicPageProvider-DlsCaR5v.d.ts} +33 -72
  32. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  33. package/dist/api-Y4MQWOFW.js +4 -0
  34. package/dist/audit-MYQXYZFU.js +3 -0
  35. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  36. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  37. package/dist/{chunk-UPPMRMYG.js → chunk-5X4QLXRG.js} +73 -151
  38. package/dist/chunk-6F3IILHI.js +62 -0
  39. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  40. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  41. package/dist/{chunk-FMUCXFII.js → chunk-7ILTDCL2.js} +9 -5
  42. package/dist/{chunk-M43Y4SSO.js → chunk-A3W6LW53.js} +15 -13
  43. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  44. package/dist/{chunk-HU2C6SSC.js → chunk-BM4CQ5P3.js} +606 -559
  45. package/dist/chunk-C7NSAPTL.js +1 -0
  46. package/dist/{chunk-J36DSWQK.js → chunk-FEJLJNWA.js} +7 -41
  47. package/dist/{chunk-IHB5DR3H.js → chunk-FTCRZOG2.js} +188 -387
  48. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  49. package/dist/chunk-GHYHJTYV.js +994 -0
  50. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  51. package/dist/{chunk-FFQEQTNW.js → chunk-IUBRCBSY.js} +134 -45
  52. package/dist/{chunk-6COVEUS7.js → chunk-JGWDVX64.js} +983 -1034
  53. package/dist/{chunk-RGAWHO7N.js → chunk-L4XMVJKY.js} +77 -222
  54. package/dist/chunk-MBADTM7L.js +64 -0
  55. package/dist/{chunk-M7MPQISP.js → chunk-OJ4SKRSV.js} +3 -16
  56. package/dist/{chunk-IVOFDYWT.js → chunk-Q7Q7V5NV.js} +2109 -1604
  57. package/dist/{chunk-JGRYX5UX.js → chunk-S7DKJPLT.js} +29 -58
  58. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  59. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  60. package/dist/{chunk-NTM7ZSB6.js → chunk-VBCS3DUA.js} +261 -168
  61. package/dist/{chunk-EFN2EIMK.js → chunk-ZFYPMX46.js} +271 -87
  62. package/dist/{chunk-L4OXEN46.js → chunk-ZKAWKYT4.js} +10 -24
  63. package/dist/components.d.ts +7 -5
  64. package/dist/components.js +46 -257
  65. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  66. package/dist/eslint-rules/index.cjs +35 -0
  67. package/{src/eslint-rules/pace-core-compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +234 -235
  68. package/dist/eslint-rules/rules/04-code-quality.cjs +290 -0
  69. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  70. package/dist/eslint-rules/rules/06-security-rbac.cjs +806 -0
  71. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +263 -0
  72. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  73. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  74. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  75. package/dist/hooks.d.ts +6 -6
  76. package/dist/hooks.js +62 -172
  77. package/dist/icons/index.d.ts +1 -0
  78. package/dist/icons/index.js +1 -0
  79. package/dist/index.d.ts +12 -11
  80. package/dist/index.js +67 -660
  81. package/dist/providers.d.ts +2 -2
  82. package/dist/providers.js +8 -35
  83. package/dist/rbac/eslint-rules.d.ts +46 -44
  84. package/dist/rbac/eslint-rules.js +7 -4
  85. package/dist/rbac/index.d.ts +109 -586
  86. package/dist/rbac/index.js +14 -207
  87. package/dist/styles/index.js +2 -12
  88. package/dist/theming/runtime.d.ts +14 -1
  89. package/dist/theming/runtime.js +3 -19
  90. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  91. package/dist/{types-CkbwOr4Y.d.ts → types-DXstZpNI.d.ts} +4 -17
  92. package/dist/types-t9H8qKRw.d.ts +55 -0
  93. package/dist/types.d.ts +1 -1
  94. package/dist/types.js +7 -94
  95. package/dist/{usePublicRouteParams-ClnV4tnv.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +20 -20
  96. package/dist/utils.d.ts +24 -117
  97. package/dist/utils.js +54 -392
  98. package/docs/README.md +17 -7
  99. package/docs/api/README.md +4 -402
  100. package/docs/api/modules.md +301 -871
  101. package/docs/api-reference/components.md +21 -21
  102. package/docs/api-reference/deprecated.md +31 -6
  103. package/docs/api-reference/hooks.md +80 -80
  104. package/docs/api-reference/rpc-functions.md +78 -3
  105. package/docs/api-reference/types.md +1 -1
  106. package/docs/api-reference/utilities.md +1 -1
  107. package/docs/architecture/README.md +1 -1
  108. package/docs/core-concepts/events.md +3 -3
  109. package/docs/core-concepts/organisations.md +6 -6
  110. package/docs/core-concepts/permissions.md +6 -6
  111. package/docs/documentation-index.md +12 -18
  112. package/docs/getting-started/cursor-rules.md +3 -23
  113. package/docs/getting-started/dependencies.md +650 -0
  114. package/docs/getting-started/documentation-index.md +1 -1
  115. package/docs/getting-started/examples/README.md +4 -4
  116. package/docs/getting-started/examples/full-featured-app.md +1 -1
  117. package/docs/getting-started/faq.md +2 -2
  118. package/docs/getting-started/installation-guide.md +20 -7
  119. package/docs/getting-started/quick-reference.md +4 -4
  120. package/docs/getting-started/quick-start.md +23 -12
  121. package/docs/implementation-guides/authentication.md +15 -15
  122. package/docs/implementation-guides/component-styling.md +1 -1
  123. package/docs/implementation-guides/data-tables.md +126 -33
  124. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  125. package/docs/implementation-guides/dynamic-colors.md +3 -3
  126. package/docs/implementation-guides/file-upload-storage.md +2 -2
  127. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  128. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  129. package/docs/implementation-guides/large-datasets.md +3 -2
  130. package/docs/implementation-guides/organisation-security.md +2 -2
  131. package/docs/implementation-guides/performance.md +2 -2
  132. package/docs/implementation-guides/permission-enforcement.md +5 -1
  133. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  134. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  135. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  136. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  137. package/docs/rbac/README.md +17 -8
  138. package/docs/rbac/advanced-patterns.md +6 -6
  139. package/docs/rbac/api-reference.md +20 -20
  140. package/docs/rbac/edge-functions-guide.md +376 -0
  141. package/docs/rbac/event-based-apps.md +3 -3
  142. package/docs/rbac/examples.md +41 -41
  143. package/docs/rbac/getting-started.md +37 -37
  144. package/docs/rbac/performance.md +1 -1
  145. package/docs/rbac/quick-start.md +52 -52
  146. package/docs/rbac/secure-client-protection.md +1 -35
  147. package/docs/rbac/troubleshooting.md +1 -1
  148. package/docs/security/README.md +5 -5
  149. package/docs/standards/0-standards-overview.md +220 -0
  150. package/docs/standards/1-pace-core-compliance-standards.md +986 -0
  151. package/docs/standards/2-project-structure-standards.md +949 -0
  152. package/docs/standards/3-architecture-standards.md +606 -0
  153. package/docs/standards/4-code-quality-standards.md +728 -0
  154. package/docs/standards/5-styling-standards.md +348 -0
  155. package/docs/standards/{07-rbac-and-rls-standard.md → 6-security-rbac-standards.md} +269 -66
  156. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  157. package/docs/standards/8-testing-documentation-standards.md +401 -0
  158. package/docs/standards/9-operations-standards.md +1102 -0
  159. package/docs/standards/README.md +185 -57
  160. package/docs/troubleshooting/README.md +4 -4
  161. package/docs/troubleshooting/common-issues.md +2 -2
  162. package/docs/troubleshooting/debugging.md +9 -9
  163. package/docs/troubleshooting/migration.md +4 -4
  164. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  165. package/eslint-config-pace-core.cjs +33 -6
  166. package/package.json +35 -23
  167. package/scripts/install-cursor-rules.cjs +25 -6
  168. package/scripts/install-eslint-config.cjs +284 -0
  169. package/src/__tests__/fixtures/supabase.ts +1 -1
  170. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +3 -3
  171. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  172. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  173. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  174. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +13 -13
  175. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  176. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  177. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  178. package/src/__tests__/public-recipe-view.test.ts +38 -9
  179. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  180. package/src/__tests__/templates/accessibility.test.template.tsx +9 -9
  181. package/src/__tests__/templates/component.test.template.tsx +18 -15
  182. package/src/components/Button/Button.tsx +5 -1
  183. package/src/components/Calendar/Calendar.tsx +201 -47
  184. package/src/components/ContextSelector/ContextSelector.tsx +106 -119
  185. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  186. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +10 -2
  187. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +10 -4
  188. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  189. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  190. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  191. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  192. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  193. package/src/components/DataTable/components/DataTableLayout.tsx +35 -21
  194. package/src/components/DataTable/components/EditFields.tsx +23 -3
  195. package/src/components/DataTable/components/EditableRow.tsx +12 -9
  196. package/src/components/DataTable/components/EmptyState.tsx +10 -9
  197. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  198. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  199. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  200. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  201. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  202. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  203. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  204. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  205. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  206. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  207. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +41 -27
  208. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  209. package/src/components/DataTable/components/index.ts +2 -1
  210. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  211. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  212. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  213. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  214. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  215. package/src/components/DataTable/types.ts +5 -18
  216. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  217. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +2 -1
  218. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  219. package/src/components/DateTimeField/DateTimeField.tsx +10 -9
  220. package/src/components/Dialog/Dialog.test.tsx +128 -104
  221. package/src/components/Dialog/Dialog.tsx +742 -24
  222. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  223. package/src/components/FileDisplay/FileDisplay.test.tsx +4 -2
  224. package/src/components/FileDisplay/FileDisplay.tsx +23 -17
  225. package/src/components/FileUpload/FileUpload.test.tsx +52 -14
  226. package/src/components/FileUpload/FileUpload.tsx +112 -130
  227. package/src/components/Form/Form.test.tsx +6 -8
  228. package/src/components/Form/Form.tsx +365 -4
  229. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  230. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  231. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  232. package/src/components/PaceAppLayout/PaceAppLayout.tsx +11 -15
  233. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  234. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  235. package/src/components/Progress/Progress.tsx +2 -4
  236. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  237. package/src/components/Select/Select.tsx +109 -98
  238. package/src/components/Select/types.ts +4 -1
  239. package/src/components/UserMenu/UserMenu.tsx +9 -6
  240. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  241. package/src/hooks/__tests__/hooks.integration.test.tsx +55 -57
  242. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  243. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +97 -97
  244. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  245. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  246. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  247. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  248. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  249. package/src/hooks/public/usePublicEvent.ts +67 -195
  250. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  251. package/src/hooks/public/usePublicEventLogo.ts +24 -14
  252. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  253. package/src/hooks/public/usePublicRouteParams.ts +5 -5
  254. package/src/hooks/useAppConfig.ts +28 -26
  255. package/src/hooks/useEventTheme.test.ts +217 -239
  256. package/src/hooks/useEventTheme.ts +16 -28
  257. package/src/hooks/useFileDisplay.ts +2 -2
  258. package/src/hooks/useOrganisationPermissions.ts +5 -7
  259. package/src/hooks/useQueryCache.ts +0 -1
  260. package/src/hooks/useSessionDraft.ts +380 -0
  261. package/src/hooks/useSessionRestoration.ts +3 -1
  262. package/src/icons/index.ts +27 -0
  263. package/src/index.ts +5 -0
  264. package/src/providers/OrganisationProvider.tsx +23 -14
  265. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  266. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  267. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  268. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  269. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  270. package/src/providers/__tests__/ProviderLifecycle.test.tsx +37 -37
  271. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  272. package/src/providers/services/EventServiceProvider.tsx +1 -24
  273. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  274. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  275. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +13 -10
  276. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  277. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  278. package/src/rbac/adapters.tsx +7 -295
  279. package/src/rbac/api.test.ts +44 -56
  280. package/src/rbac/api.ts +10 -17
  281. package/src/rbac/cache-invalidation.ts +0 -1
  282. package/src/rbac/compliance/index.ts +10 -0
  283. package/src/rbac/compliance/pattern-detector.ts +553 -0
  284. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  285. package/src/rbac/components/AccessDenied.tsx +150 -0
  286. package/src/rbac/components/NavigationGuard.tsx +12 -20
  287. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  288. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  289. package/src/rbac/components/index.ts +3 -41
  290. package/src/rbac/eslint-rules.js +1 -1
  291. package/src/rbac/hooks/index.ts +0 -3
  292. package/src/rbac/hooks/permissions/index.ts +0 -3
  293. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  294. package/src/rbac/hooks/usePermissions.ts +0 -3
  295. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  296. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  297. package/src/rbac/hooks/useResourcePermissions.test.ts +124 -38
  298. package/src/rbac/hooks/useResourcePermissions.ts +139 -48
  299. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  300. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  301. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  302. package/src/rbac/index.ts +7 -9
  303. package/src/rbac/utils/contextValidator.ts +9 -7
  304. package/src/services/AuthService.ts +130 -18
  305. package/src/services/EventService.ts +4 -97
  306. package/src/services/InactivityService.ts +16 -0
  307. package/src/services/OrganisationService.ts +7 -44
  308. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  309. package/src/services/base/BaseService.ts +0 -3
  310. package/src/styles/core.css +7 -0
  311. package/src/theming/__tests__/parseEventColours.test.ts +9 -3
  312. package/src/theming/parseEventColours.ts +22 -10
  313. package/src/types/database.generated.ts +4733 -3809
  314. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  315. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  316. package/src/utils/context/organisationContext.test.ts +13 -28
  317. package/src/utils/context/organisationContext.ts +21 -52
  318. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  319. package/src/utils/file-reference/index.ts +39 -15
  320. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  321. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  322. package/src/utils/index.ts +4 -1
  323. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  324. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  325. package/src/utils/persistence/keyDerivation.ts +304 -0
  326. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  327. package/src/utils/security/secureStorage.ts +5 -5
  328. package/src/utils/storage/README.md +1 -1
  329. package/src/utils/storage/helpers.ts +3 -3
  330. package/src/utils/supabase/createBaseClient.ts +147 -0
  331. package/src/utils/timezone/timezone.test.ts +1 -2
  332. package/src/utils/timezone/timezone.ts +1 -1
  333. package/src/utils/validation/csrf.ts +4 -4
  334. package/cursor-rules/00-pace-core-compliance.mdc +0 -331
  335. package/cursor-rules/01-standards-compliance.mdc +0 -244
  336. package/cursor-rules/04-testing-standards.mdc +0 -268
  337. package/cursor-rules/05-bug-reports-and-features.mdc +0 -246
  338. package/cursor-rules/06-code-quality.mdc +0 -309
  339. package/cursor-rules/07-tech-stack-compliance.mdc +0 -214
  340. package/cursor-rules/CHANGELOG.md +0 -119
  341. package/cursor-rules/README.md +0 -192
  342. package/dist/DataTable-AOVNCPTX.js +0 -175
  343. package/dist/DataTable-AOVNCPTX.js.map +0 -1
  344. package/dist/UnifiedAuthProvider-4SBX4LU5.js +0 -18
  345. package/dist/UnifiedAuthProvider-4SBX4LU5.js.map +0 -1
  346. package/dist/api-O6HTBX5Y.js +0 -52
  347. package/dist/api-O6HTBX5Y.js.map +0 -1
  348. package/dist/audit-V53FV5AG.js +0 -17
  349. package/dist/audit-V53FV5AG.js.map +0 -1
  350. package/dist/chunk-5DRSZLL2.js.map +0 -1
  351. package/dist/chunk-63FOKYGO.js.map +0 -1
  352. package/dist/chunk-6COVEUS7.js.map +0 -1
  353. package/dist/chunk-AFVQODI2.js +0 -263
  354. package/dist/chunk-AFVQODI2.js.map +0 -1
  355. package/dist/chunk-DGUM43GV.js.map +0 -1
  356. package/dist/chunk-E66EQZE6.js.map +0 -1
  357. package/dist/chunk-EFN2EIMK.js.map +0 -1
  358. package/dist/chunk-FFQEQTNW.js.map +0 -1
  359. package/dist/chunk-FMUCXFII.js.map +0 -1
  360. package/dist/chunk-G37KK66H.js.map +0 -1
  361. package/dist/chunk-G7QEZTYQ.js +0 -2053
  362. package/dist/chunk-G7QEZTYQ.js.map +0 -1
  363. package/dist/chunk-HU2C6SSC.js.map +0 -1
  364. package/dist/chunk-IHB5DR3H.js.map +0 -1
  365. package/dist/chunk-IVOFDYWT.js.map +0 -1
  366. package/dist/chunk-J36DSWQK.js.map +0 -1
  367. package/dist/chunk-JGRYX5UX.js.map +0 -1
  368. package/dist/chunk-KQCRWDSA.js +0 -1
  369. package/dist/chunk-KQCRWDSA.js.map +0 -1
  370. package/dist/chunk-L4OXEN46.js.map +0 -1
  371. package/dist/chunk-LMC26NLJ.js +0 -84
  372. package/dist/chunk-LMC26NLJ.js.map +0 -1
  373. package/dist/chunk-M43Y4SSO.js.map +0 -1
  374. package/dist/chunk-M7MPQISP.js.map +0 -1
  375. package/dist/chunk-NTM7ZSB6.js.map +0 -1
  376. package/dist/chunk-PWLANIRT.js.map +0 -1
  377. package/dist/chunk-QXHPKYJV.js.map +0 -1
  378. package/dist/chunk-RGAWHO7N.js.map +0 -1
  379. package/dist/chunk-UPPMRMYG.js.map +0 -1
  380. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  381. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  382. package/dist/components.js.map +0 -1
  383. package/dist/contextValidator-5OGXSPKS.js +0 -9
  384. package/dist/contextValidator-5OGXSPKS.js.map +0 -1
  385. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  386. package/dist/hooks.js.map +0 -1
  387. package/dist/index.js.map +0 -1
  388. package/dist/providers.js.map +0 -1
  389. package/dist/rbac/eslint-rules.js.map +0 -1
  390. package/dist/rbac/index.js.map +0 -1
  391. package/dist/styles/index.js.map +0 -1
  392. package/dist/theming/runtime.js.map +0 -1
  393. package/dist/types.js.map +0 -1
  394. package/dist/utils.js.map +0 -1
  395. package/docs/best-practices/README.md +0 -472
  396. package/docs/best-practices/accessibility.md +0 -601
  397. package/docs/best-practices/common-patterns.md +0 -516
  398. package/docs/best-practices/deployment.md +0 -1103
  399. package/docs/best-practices/performance.md +0 -1328
  400. package/docs/best-practices/security.md +0 -940
  401. package/docs/best-practices/testing.md +0 -1034
  402. package/docs/rbac/compliance/compliance-guide.md +0 -544
  403. package/docs/standards/01-architecture-standard.md +0 -44
  404. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  405. package/docs/standards/03-component-standard.md +0 -32
  406. package/docs/standards/04-code-style-standard.md +0 -32
  407. package/docs/standards/05-security-standard.md +0 -44
  408. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  409. package/docs/standards/pace-core-compliance.md +0 -432
  410. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  411. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  412. package/scripts/audit/core/checks/bundle.cjs +0 -142
  413. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  414. package/scripts/audit/core/checks/config.cjs +0 -54
  415. package/scripts/audit/core/checks/coverage.cjs +0 -84
  416. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  417. package/scripts/audit/core/checks/documentation.cjs +0 -268
  418. package/scripts/audit/core/checks/environment.cjs +0 -116
  419. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  420. package/scripts/audit/core/checks/forms.cjs +0 -172
  421. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  422. package/scripts/audit/core/checks/hooks.cjs +0 -334
  423. package/scripts/audit/core/checks/imports.cjs +0 -244
  424. package/scripts/audit/core/checks/performance.cjs +0 -325
  425. package/scripts/audit/core/checks/routes.cjs +0 -117
  426. package/scripts/audit/core/checks/state.cjs +0 -130
  427. package/scripts/audit/core/checks/structure.cjs +0 -65
  428. package/scripts/audit/core/checks/style.cjs +0 -584
  429. package/scripts/audit/core/checks/testing.cjs +0 -122
  430. package/scripts/audit/core/checks/typescript.cjs +0 -61
  431. package/scripts/audit/core/scanner.cjs +0 -199
  432. package/scripts/audit/core/utils.cjs +0 -137
  433. package/scripts/audit/index.cjs +0 -223
  434. package/scripts/audit/reporters/console.cjs +0 -151
  435. package/scripts/audit/reporters/json.cjs +0 -54
  436. package/scripts/audit/reporters/markdown.cjs +0 -124
  437. package/scripts/audit-consuming-app.cjs +0 -86
  438. package/src/components/DataTable/components/DataTableBody.tsx +0 -454
  439. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  440. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  441. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  442. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  443. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  444. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  445. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  446. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  447. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  448. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  449. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  450. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  451. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  452. package/src/components/DataTable/utils/debugTools.ts +0 -514
  453. package/src/eslint-rules/pace-core-compliance.js +0 -638
  454. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  455. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  456. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  457. package/src/rbac/components/NavigationProvider.tsx +0 -345
  458. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  459. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  460. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  461. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  462. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  463. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  464. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  465. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  466. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  467. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  468. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  469. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  470. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  471. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  472. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  473. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -15,19 +15,19 @@ import { renderWithProviders } from '../../__tests__/helpers/test-utils';
15
15
 
16
16
  // Mock the DataTable component
17
17
  vi.mock('../../components/DataTable', () => ({
18
- DataTable: vi.fn(() => <div data-testid="data-table">DataTable Component</div>)
18
+ DataTable: vi.fn(() => <section data-testid="data-table">DataTable Component</section>)
19
19
  }));
20
20
 
21
21
  // Mock the LoadingSpinner component
22
22
  vi.mock('../../components/LoadingSpinner/LoadingSpinner', () => ({
23
- LoadingSpinner: vi.fn(() => <div data-testid="loading-spinner">Loading...</div>)
23
+ LoadingSpinner: vi.fn(() => <p data-testid="loading-spinner">Loading...</p>)
24
24
  }));
25
25
 
26
26
  describe('LazyLoad Utility', () => {
27
27
  describe('createLazyComponent', () => {
28
28
  it('should create a lazy component with default fallback', async () => {
29
29
  const mockImportFn = vi.fn().mockResolvedValue({
30
- default: () => <div data-testid="lazy-component">Lazy Component</div>
30
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
31
31
  });
32
32
 
33
33
  const LazyTestComponent = createLazyComponent(
@@ -38,11 +38,11 @@ describe('LazyLoad Utility', () => {
38
38
  renderWithProviders(<LazyTestComponent />);
39
39
 
40
40
  // Should show loading spinner initially
41
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
41
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
42
42
 
43
43
  // Wait for the component to load
44
44
  await waitFor(() => {
45
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
45
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
46
46
  });
47
47
 
48
48
  expect(mockImportFn).toHaveBeenCalledTimes(1);
@@ -50,10 +50,10 @@ describe('LazyLoad Utility', () => {
50
50
 
51
51
  it('should create a lazy component with custom fallback', async () => {
52
52
  const mockImportFn = vi.fn().mockResolvedValue({
53
- default: () => <div data-testid="lazy-component">Lazy Component</div>
53
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
54
54
  });
55
55
 
56
- const customFallback = <div data-testid="custom-fallback">Custom Loading...</div>;
56
+ const customFallback = <p data-testid="custom-fallback">Custom Loading...</p>;
57
57
 
58
58
  const LazyTestComponent = createLazyComponent(
59
59
  mockImportFn,
@@ -64,21 +64,21 @@ describe('LazyLoad Utility', () => {
64
64
  renderWithProviders(<LazyTestComponent />);
65
65
 
66
66
  // Should show custom fallback initially
67
- expect(screen.getByTestId('custom-fallback')).toBeInTheDocument();
67
+ expect(screen.getByTestId('custom-fallback')).toBeDefined();
68
68
 
69
69
  // Wait for the component to load
70
70
  await waitFor(() => {
71
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
71
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
72
72
  });
73
73
  });
74
74
 
75
75
  it('should create a lazy component with error boundary', async () => {
76
76
  const mockImportFn = vi.fn().mockResolvedValue({
77
- default: () => <div data-testid="lazy-component">Lazy Component</div>
77
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
78
78
  });
79
79
 
80
80
  const ErrorBoundary = ({ children }: { children: React.ReactNode }) => (
81
- <div data-testid="error-boundary">{children}</div>
81
+ <section data-testid="error-boundary">{children}</section>
82
82
  );
83
83
 
84
84
  const LazyTestComponent = createLazyComponent(
@@ -90,15 +90,15 @@ describe('LazyLoad Utility', () => {
90
90
  renderWithProviders(<LazyTestComponent />);
91
91
 
92
92
  // Should show loading spinner initially
93
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
93
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
94
94
 
95
95
  // Wait for the component to load
96
96
  await waitFor(() => {
97
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
97
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
98
98
  });
99
99
 
100
100
  // Error boundary should wrap the component
101
- expect(screen.getByTestId('error-boundary')).toBeInTheDocument();
101
+ expect(screen.getByTestId('error-boundary')).toBeDefined();
102
102
  });
103
103
 
104
104
  it('should handle import errors gracefully', async () => {
@@ -121,7 +121,7 @@ describe('LazyLoad Utility', () => {
121
121
 
122
122
  render() {
123
123
  if (this.state.hasError) {
124
- return <div data-testid="error-display">Error occurred</div>;
124
+ return <p data-testid="error-display">Error occurred</p>;
125
125
  }
126
126
  return this.props.children;
127
127
  }
@@ -139,11 +139,11 @@ describe('LazyLoad Utility', () => {
139
139
  renderWithProviders(<LazyTestComponent />);
140
140
 
141
141
  // Should show loading spinner initially
142
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
142
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
143
143
 
144
144
  // Wait for error to be caught and displayed
145
145
  await waitFor(() => {
146
- expect(screen.getByTestId('error-display')).toBeInTheDocument();
146
+ expect(screen.getByTestId('error-display')).toBeDefined();
147
147
  }, { timeout: 2000 });
148
148
 
149
149
  // The import function should have been called
@@ -154,7 +154,7 @@ describe('LazyLoad Utility', () => {
154
154
 
155
155
  it('should set display name correctly', async () => {
156
156
  const mockImportFn = vi.fn().mockResolvedValue({
157
- default: () => <div data-testid="lazy-component">Lazy Component</div>
157
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
158
158
  });
159
159
 
160
160
  const LazyTestComponent = createLazyComponent(
@@ -168,9 +168,9 @@ describe('LazyLoad Utility', () => {
168
168
  it('should pass props to the lazy component', async () => {
169
169
  const mockImportFn = vi.fn().mockResolvedValue({
170
170
  default: ({ title, count }: { title: string; count: number }) => (
171
- <div data-testid="lazy-component">
171
+ <section data-testid="lazy-component">
172
172
  {title}: {count}
173
- </div>
173
+ </section>
174
174
  )
175
175
  });
176
176
 
@@ -189,7 +189,7 @@ describe('LazyLoad Utility', () => {
189
189
  it('should handle multiple instances of the same lazy component', async () => {
190
190
  const mockImportFn = vi.fn().mockResolvedValue({
191
191
  default: ({ id }: { id: string }) => (
192
- <div data-testid={`lazy-component-${id}`}>Component {id}</div>
192
+ <section data-testid={`lazy-component-${id}`}>Component {id}</section>
193
193
  )
194
194
  });
195
195
 
@@ -199,15 +199,15 @@ describe('LazyLoad Utility', () => {
199
199
  );
200
200
 
201
201
  renderWithProviders(
202
- <div>
202
+ <section>
203
203
  <LazyTestComponent id="1" />
204
204
  <LazyTestComponent id="2" />
205
- </div>
205
+ </section>
206
206
  );
207
207
 
208
208
  await waitFor(() => {
209
- expect(screen.getByTestId('lazy-component-1')).toBeInTheDocument();
210
- expect(screen.getByTestId('lazy-component-2')).toBeInTheDocument();
209
+ expect(screen.getByTestId('lazy-component-1')).toBeDefined();
210
+ expect(screen.getByTestId('lazy-component-2')).toBeDefined();
211
211
  });
212
212
 
213
213
  // Import function should only be called once due to React.lazy caching
@@ -219,37 +219,40 @@ describe('LazyLoad Utility', () => {
219
219
  it('should render the DataTable component when loaded', async () => {
220
220
  const mockProps = {
221
221
  data: [{ id: 1, name: 'Test' }],
222
- columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }]
222
+ columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }],
223
+ rbac: { pageName: 'test-page' }
223
224
  };
224
225
 
225
226
  renderWithProviders(<LazyDataTable {...mockProps} />);
226
227
 
227
228
  // Should show loading spinner initially
228
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
229
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
229
230
 
230
231
  // Wait for the DataTable to load
231
232
  await waitFor(() => {
232
- expect(screen.getByTestId('data-table')).toBeInTheDocument();
233
+ expect(screen.getByTestId('data-table')).toBeDefined();
233
234
  });
234
235
  });
235
236
 
236
237
  it('should pass props to the DataTable component', async () => {
237
238
  const mockProps = {
238
239
  data: [{ id: 1, name: 'Test' }],
239
- columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }]
240
+ columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }],
241
+ rbac: { pageName: 'test-page' }
240
242
  };
241
243
 
242
244
  renderWithProviders(<LazyDataTable {...mockProps} />);
243
245
 
244
246
  await waitFor(() => {
245
- expect(screen.getByTestId('data-table')).toBeInTheDocument();
247
+ expect(screen.getByTestId('data-table')).toBeDefined();
246
248
  });
247
249
  });
248
250
 
249
251
  it('should render without errors', () => {
250
252
  const mockProps = {
251
253
  data: [{ id: 1, name: 'Test' }],
252
- columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }]
254
+ columns: [{ id: 'name', accessorKey: 'name', header: 'Name' }],
255
+ rbac: { pageName: 'test-page' }
253
256
  };
254
257
 
255
258
  expect(() => renderWithProviders(<LazyDataTable {...mockProps} />)).not.toThrow();
@@ -259,7 +262,7 @@ describe('LazyLoad Utility', () => {
259
262
  describe('Component Integration', () => {
260
263
  it('should work with React Suspense boundaries', async () => {
261
264
  const mockImportFn = vi.fn().mockResolvedValue({
262
- default: () => <div data-testid="lazy-component">Lazy Component</div>
265
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
263
266
  });
264
267
 
265
268
  const LazyTestComponent = createLazyComponent(
@@ -268,23 +271,23 @@ describe('LazyLoad Utility', () => {
268
271
  );
269
272
 
270
273
  const TestWrapper = () => (
271
- <div data-testid="wrapper">
274
+ <section data-testid="wrapper">
272
275
  <LazyTestComponent />
273
- </div>
276
+ </section>
274
277
  );
275
278
 
276
279
  renderWithProviders(<TestWrapper />);
277
280
 
278
281
  // Should show loading spinner initially
279
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
282
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
280
283
 
281
284
  // Wait for the component to load
282
285
  await waitFor(() => {
283
- expect(screen.getByTestId('lazy-component')).toBeInTheDocument();
286
+ expect(screen.getByTestId('lazy-component')).toBeDefined();
284
287
  });
285
288
 
286
289
  // Wrapper should still be present
287
- expect(screen.getByTestId('wrapper')).toBeInTheDocument();
290
+ expect(screen.getByTestId('wrapper')).toBeDefined();
288
291
  });
289
292
 
290
293
  it('should handle unmounting before load completes', async () => {
@@ -292,7 +295,7 @@ describe('LazyLoad Utility', () => {
292
295
  new Promise(resolve => {
293
296
  setTimeout(() => {
294
297
  resolve({
295
- default: () => <div data-testid="lazy-component">Lazy Component</div>
298
+ default: () => <section data-testid="lazy-component">Lazy Component</section>
296
299
  });
297
300
  }, 100);
298
301
  })
@@ -306,7 +309,7 @@ describe('LazyLoad Utility', () => {
306
309
  const { unmount } = renderWithProviders(<LazyTestComponent />);
307
310
 
308
311
  // Should show loading spinner initially
309
- expect(screen.getByTestId('loading-spinner')).toBeInTheDocument();
312
+ expect(screen.getByTestId('loading-spinner')).toBeDefined();
310
313
 
311
314
  // Unmount before load completes
312
315
  unmount();
@@ -24,16 +24,16 @@ describe('organisationContext', () => {
24
24
  });
25
25
 
26
26
  describe('setOrganisationContext', () => {
27
- it('should set organisation context successfully', async () => {
27
+ it('should set organisation context successfully (no-op)', async () => {
28
28
  const organisationId = 'org-123';
29
29
  const mockRpc = vi.fn().mockResolvedValue({ error: null });
30
30
  mockSupabase.rpc = mockRpc;
31
31
 
32
+ // setOrganisationContext is now a no-op (deprecated)
32
33
  await setOrganisationContext(mockSupabase, organisationId);
33
34
 
34
- expect(mockRpc).toHaveBeenCalledWith('set_organisation_context', {
35
- org_id: organisationId
36
- });
35
+ // Should not call rpc since it's a no-op
36
+ expect(mockRpc).not.toHaveBeenCalled();
37
37
  });
38
38
 
39
39
  it('should handle missing supabase client gracefully', async () => {
@@ -153,14 +153,13 @@ describe('organisationContext', () => {
153
153
  });
154
154
 
155
155
  describe('isOrganisationContextAvailable', () => {
156
- it('should return true when functions are available', async () => {
157
- const mockRpc = vi.fn().mockResolvedValue({ error: null });
158
- mockSupabase.rpc = mockRpc;
159
-
156
+ it('should return false (deprecated function)', async () => {
157
+ // isOrganisationContextAvailable is deprecated and always returns false
160
158
  const result = await isOrganisationContextAvailable(mockSupabase);
161
159
 
162
- expect(mockRpc).toHaveBeenCalledWith('get_organisation_context');
163
- expect(result).toBe(true);
160
+ // Should not call RPC since function is deprecated
161
+ expect(mockSupabase.rpc).not.toHaveBeenCalled();
162
+ expect(result).toBe(false);
164
163
  });
165
164
 
166
165
  it('should return false when supabase client is missing', async () => {
@@ -29,17 +29,13 @@ describe('Organisation Context', () => {
29
29
  });
30
30
 
31
31
  describe('setOrganisationContext', () => {
32
- it('sets organisation context successfully', async () => {
33
- mockSupabase.rpc.mockResolvedValue({
34
- data: null,
35
- error: null
36
- });
37
-
32
+ it('sets organisation context successfully (no-op)', async () => {
33
+ // setOrganisationContext is now a no-op (deprecated)
34
+ // It should complete without calling rpc
38
35
  await setOrganisationContext(mockSupabase, 'org-123');
39
36
 
40
- expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', {
41
- org_id: 'org-123'
42
- });
37
+ // Should not call rpc since it's a no-op
38
+ expect(mockSupabase.rpc).not.toHaveBeenCalled();
43
39
  });
44
40
 
45
41
  it('handles missing supabase client gracefully', async () => {
@@ -180,20 +176,14 @@ describe('Organisation Context', () => {
180
176
  });
181
177
 
182
178
  it('handles complete workflow', async () => {
183
- // Set context
184
- mockSupabase.rpc.mockResolvedValueOnce({
185
- data: null,
186
- error: null
187
- });
188
-
179
+ // setOrganisationContext is now a no-op, so it won't call rpc
189
180
  await setOrganisationContext(mockSupabase, 'org-123');
190
181
 
191
- // Get context
182
+ // getOrganisationContext always returns null (deprecated)
192
183
  const result = await getOrganisationContext(mockSupabase);
193
-
194
184
  expect(result).toBeNull();
195
185
 
196
- // Clear context
186
+ // clearOrganisationContext still calls rpc
197
187
  mockSupabase.rpc.mockResolvedValueOnce({
198
188
  data: null,
199
189
  error: null
@@ -201,25 +191,20 @@ describe('Organisation Context', () => {
201
191
 
202
192
  await clearOrganisationContext(mockSupabase);
203
193
 
204
- expect(mockSupabase.rpc).toHaveBeenCalledTimes(2);
194
+ // Only clearOrganisationContext should call rpc (once)
195
+ expect(mockSupabase.rpc).toHaveBeenCalledTimes(1);
205
196
  });
206
197
 
207
198
  it('handles multiple organisation switches', async () => {
208
199
  const organisations = ['org-123', 'org-456', 'org-789'];
209
200
 
201
+ // setOrganisationContext is now a no-op, so it won't call rpc
210
202
  for (const orgId of organisations) {
211
- mockSupabase.rpc.mockResolvedValue({
212
- data: null,
213
- error: null
214
- });
215
-
216
203
  await setOrganisationContext(mockSupabase, orgId);
217
204
  }
218
205
 
219
- expect(mockSupabase.rpc).toHaveBeenCalledTimes(3);
220
- expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', { org_id: 'org-123' });
221
- expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', { org_id: 'org-456' });
222
- expect(mockSupabase.rpc).toHaveBeenCalledWith('set_organisation_context', { org_id: 'org-789' });
206
+ // setOrganisationContext is deprecated and doesn't call rpc anymore
207
+ expect(mockSupabase.rpc).not.toHaveBeenCalled();
223
208
  });
224
209
  });
225
210
 
@@ -16,47 +16,25 @@ const log = createLogger('organisationContext');
16
16
  /**
17
17
  * Set organisation context in the database session
18
18
  *
19
- * This function attempts to set the organisation context using a database function.
20
- * If the function is not available, it falls back gracefully without throwing errors.
19
+ * @deprecated This function is a no-op. Organisation context is now handled via:
20
+ * - Secure Supabase client headers (useSecureSupabase hook)
21
+ * - Explicit p_organisation_id parameters in RPC calls
22
+ * - RLS policies that use auth.uid() and organisation_id columns
21
23
  *
22
- * @param supabase - Supabase client instance
23
- * @param organisationId - The organisation ID to set as context
24
- * @returns Promise that resolves when context is set (or falls back gracefully)
24
+ * This function is kept for backward compatibility but does nothing.
25
+ *
26
+ * @param supabase - Supabase client instance (unused)
27
+ * @param organisationId - The organisation ID (unused)
28
+ * @returns Promise that resolves immediately
25
29
  */
26
30
  export async function setOrganisationContext(
27
31
  supabase: SupabaseClient,
28
32
  organisationId: string
29
33
  ): Promise<void> {
30
- if (!supabase || !organisationId) {
31
- // TODO: Replace with proper logging service integration
32
- return;
33
- }
34
-
35
- try {
36
- // Add timeout to prevent hanging RPC calls
37
- const timeoutPromise = new Promise((_, reject) => {
38
- setTimeout(() => reject(new Error('RPC timeout after 3 seconds')), 3000);
39
- });
40
-
41
- // Call the database function to set organisation context
42
- const rpcPromise = supabase.rpc('set_organisation_context', {
43
- org_id: organisationId
44
- });
45
-
46
- const { error } = await Promise.race([rpcPromise, timeoutPromise]) as any;
47
-
48
- if (error) {
49
- // Function might not exist yet - this is expected during migration
50
- // Silent fail - will fall back to client-side filtering
51
- log.debug('RPC function not available or failed, continuing without database context');
52
- } else {
53
- log.debug('Organisation context set in database successfully');
54
- }
55
- } catch (error) {
56
- // Handle any other errors gracefully
57
- // Silent fail - will fall back to client-side filtering
58
- log.debug('Failed to set database context, continuing without it:', error);
59
- }
34
+ // No-op: Organisation context is now handled via secure client and explicit parameters
35
+ // This function is kept for backward compatibility
36
+ log.debug('setOrganisationContext called but is a no-op - context handled via secure client');
37
+ return Promise.resolve();
60
38
  }
61
39
 
62
40
  /**
@@ -132,25 +110,16 @@ export async function getOrganisationContext(
132
110
  /**
133
111
  * Check if organisation context functions are available in the database
134
112
  *
135
- * @param supabase - Supabase client instance
136
- * @returns Promise that resolves to true if functions are available
113
+ * @deprecated This function always returns false. Organisation context functions have been removed.
114
+ * Organisation context is now handled via secure client and explicit parameters.
115
+ *
116
+ * @param supabase - Supabase client instance (unused)
117
+ * @returns Promise that resolves to false
137
118
  */
138
119
  export async function isOrganisationContextAvailable(
139
120
  supabase: SupabaseClient
140
121
  ): Promise<boolean> {
141
- if (!supabase) {
142
- return false;
143
- }
144
-
145
- try {
146
- const { error } = await supabase.rpc('get_organisation_context');
147
-
148
- if (error) {
149
- return false;
150
- }
151
-
152
- return true;
153
- } catch (error) {
154
- return false;
155
- }
122
+ // Always return false - organisation context functions have been removed
123
+ // Context is now handled via secure client and explicit parameters
124
+ return false;
156
125
  }
@@ -73,7 +73,7 @@ export const loadFormUtils = async (): Promise<{
73
73
 
74
74
  // Dynamic CSV utilities
75
75
  export const loadCSVUtils = async (): Promise<unknown> => {
76
- // @ts-ignore - papaparse is an optional dependency provided by consuming apps
76
+ // @ts-ignore - papaparse is a dependency of pace-core, should be available via node_modules
77
77
  const papaparse = await import('papaparse');
78
78
  return papaparse.default;
79
79
  };
@@ -87,6 +87,26 @@ export class FileReferenceServiceImpl implements FileReferenceService {
87
87
  log.debug('Using authenticated user ID for user-scoped file upload', { userId: authenticatedUserId });
88
88
  }
89
89
 
90
+ // CRITICAL: Check super admin status in application layer (consistent with pace-core pattern)
91
+ // Super admins bypass all permission checks - this is handled in the application layer,
92
+ // not in RLS policies. The RPC function still validates input and handles the insert,
93
+ // but permission checks are bypassed for super admins.
94
+ let isSuperAdminUser = false;
95
+ const userIdForCheck = authenticatedUserId || options.userId;
96
+ if (userIdForCheck) {
97
+ try {
98
+ // Import isSuperAdmin from rbac/api - this is the standard way to check super admin
99
+ const { isSuperAdmin } = await import('../../rbac/api');
100
+ isSuperAdminUser = await isSuperAdmin(userIdForCheck);
101
+ if (isSuperAdminUser) {
102
+ log.debug('Super admin detected - bypassing permission checks', { userId: userIdForCheck });
103
+ }
104
+ } catch (superAdminCheckError) {
105
+ // If super admin check fails, continue with normal permission flow
106
+ log.warn('Failed to check super-admin status, proceeding with normal permission checks', superAdminCheckError);
107
+ }
108
+ }
109
+
90
110
  // Step 1: Upload file to storage bucket first
91
111
  // This generates a unique path: {orgId}/{folder}/{timestamp-uuid-filename} or users/{auth.uid()}/{folder}/{timestamp-uuid-filename}
92
112
  // Bucket is automatically selected based on is_public flag
@@ -123,6 +143,22 @@ export class FileReferenceServiceImpl implements FileReferenceService {
123
143
 
124
144
  // Step 4: Create file reference in database using RPC function
125
145
  // This links the storage path to the record in core_file_references table
146
+ // CRITICAL: Always pass the authenticated user ID to SECURITY DEFINER functions
147
+ // In SECURITY DEFINER functions, auth.uid() returns the function owner's ID,
148
+ // not the caller's ID, so we must explicitly pass the user ID
149
+ let rpcUserId: string | null = null;
150
+ if (authenticatedUserId) {
151
+ rpcUserId = authenticatedUserId;
152
+ } else if (options.userId) {
153
+ rpcUserId = options.userId;
154
+ } else {
155
+ // Get authenticated user ID from session as fallback
156
+ const { data: { user: authUser } } = await this.supabase.auth.getUser();
157
+ if (authUser) {
158
+ rpcUserId = authUser.id;
159
+ }
160
+ }
161
+
126
162
  const { data, error } = await this.supabase
127
163
  .rpc('data_file_reference_create', {
128
164
  p_table_name: options.table_name,
@@ -141,7 +177,7 @@ export class FileReferenceServiceImpl implements FileReferenceService {
141
177
  ...options.custom_metadata
142
178
  },
143
179
  p_is_public: options.is_public || false,
144
- p_user_id: authenticatedUserId || options.userId || null // Pass authenticated user ID for user-scoped files
180
+ p_user_id: rpcUserId // Always pass authenticated user ID for SECURITY DEFINER functions
145
181
  });
146
182
 
147
183
  // Step 5: Rollback - if database insert fails, clean up uploaded file
@@ -152,19 +188,6 @@ export class FileReferenceServiceImpl implements FileReferenceService {
152
188
 
153
189
  // Check if RPC returned null (permission denied or other failure)
154
190
  if (!data || data === null) {
155
- // Before throwing permission error, check if user is super-admin
156
- // If super-admin, the RPC should have allowed the upload, so this is likely a different issue
157
- let isSuperAdminUser = false;
158
- try {
159
- const { data: { user: authUser } } = await this.supabase.auth.getUser();
160
- if (authUser) {
161
- isSuperAdminUser = await isSuperAdmin(authUser.id);
162
- }
163
- } catch (superAdminCheckError) {
164
- // If super-admin check fails, continue with permission error
165
- log.warn('Failed to check super-admin status', superAdminCheckError);
166
- }
167
-
168
191
  // Clean up the uploaded file since DB insert failed
169
192
  await deleteFile(this.supabase, filePath, options.is_public || false);
170
193
 
@@ -173,7 +196,8 @@ export class FileReferenceServiceImpl implements FileReferenceService {
173
196
  const pageContextDisplay = options.pageContext || 'undefined';
174
197
 
175
198
  if (isSuperAdminUser) {
176
- // Super-admin should have been allowed - this suggests a different issue
199
+ // Super-admin should have been allowed - this suggests a database or RPC function issue
200
+ // Since we already checked super admin in the application layer, this is unexpected
177
201
  throw new Error(
178
202
  `File upload failed for super-admin user. This may indicate a database issue. ` +
179
203
  `Page context: '${pageContextDisplay}', App: '${appName}'. ` +
@@ -161,8 +161,9 @@ describe('formatDateTime Utility', () => {
161
161
  }
162
162
  const end = performance.now();
163
163
 
164
- // Should complete in reasonable time (less than 100ms for 1000 calls)
165
- expect(end - start).toBeLessThan(100);
164
+ // Should complete in reasonable time (less than 200ms for 1000 calls in test environment)
165
+ // Increased threshold to account for test environment overhead
166
+ expect(end - start).toBeLessThan(200);
166
167
  });
167
168
  });
168
169
 
@@ -127,13 +127,19 @@ export function loadGoogleMapsScript(
127
127
  return;
128
128
  }
129
129
 
130
- // Check if script is already being loaded
130
+ // Check if script is already being loaded or exists
131
131
  const existingScript = document.querySelector(
132
132
  `script[src*="maps.googleapis.com/maps/api/js"]`
133
133
  );
134
134
  if (existingScript) {
135
+ // If Google Maps is already loaded, resolve immediately
136
+ if (window.google?.maps?.places) {
137
+ resolve();
138
+ return;
139
+ }
140
+
135
141
  // Wait for existing script to load
136
- existingScript.addEventListener('load', () => {
142
+ const handleLoad = () => {
137
143
  // Wait for the library to initialize with multiple retries
138
144
  let attempts = 0;
139
145
  const maxAttempts = 20; // 2 seconds total
@@ -150,10 +156,26 @@ export function loadGoogleMapsScript(
150
156
  };
151
157
 
152
158
  checkPlaces();
153
- });
159
+ };
160
+
161
+ // Check if script already loaded
162
+ const scriptElement = existingScript as HTMLScriptElement;
163
+ if (scriptElement.getAttribute('data-loaded') === 'true') {
164
+ handleLoad();
165
+ return;
166
+ }
167
+
168
+ // Check if script is already complete (using type assertion for readyState which exists at runtime)
169
+ const scriptReadyState = (scriptElement as any).readyState;
170
+ if (scriptReadyState === 'complete' || scriptReadyState === 'loaded') {
171
+ handleLoad();
172
+ return;
173
+ }
174
+
175
+ existingScript.addEventListener('load', handleLoad, { once: true });
154
176
  existingScript.addEventListener('error', () => {
155
177
  reject(new Error('Failed to load Google Maps script'));
156
- });
178
+ }, { once: true });
157
179
  return;
158
180
  }
159
181
 
@@ -164,6 +186,9 @@ export function loadGoogleMapsScript(
164
186
  script.defer = true;
165
187
 
166
188
  script.onload = () => {
189
+ // Mark script as loaded
190
+ script.setAttribute('data-loaded', 'true');
191
+
167
192
  // Wait for the library to initialize with multiple retries
168
193
  let attempts = 0;
169
194
  const maxAttempts = 20; // 2 seconds total (20 * 100ms)