@jmruthers/pace-core 0.6.4 → 0.6.6

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 (387) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +5 -403
  3. package/core-usage-manifest.json +93 -0
  4. package/cursor-rules/00-pace-core-compliance.mdc +128 -26
  5. package/cursor-rules/01-standards-compliance.mdc +49 -8
  6. package/cursor-rules/02-project-structure.mdc +6 -0
  7. package/cursor-rules/03-solid-principles.mdc +2 -0
  8. package/cursor-rules/04-testing-standards.mdc +2 -0
  9. package/cursor-rules/05-bug-reports-and-features.mdc +2 -0
  10. package/cursor-rules/06-code-quality.mdc +2 -0
  11. package/cursor-rules/07-tech-stack-compliance.mdc +2 -0
  12. package/cursor-rules/08-markup-quality.mdc +52 -27
  13. package/cursor-rules/09-rbac-compliance.mdc +462 -0
  14. package/cursor-rules/10-error-handling-patterns.mdc +179 -0
  15. package/cursor-rules/11-performance-optimization.mdc +169 -0
  16. package/cursor-rules/12-ci-cd-integration.mdc +150 -0
  17. package/dist/{AuthService-Cb34EQs3.d.ts → AuthService-DmfO5rGS.d.ts} +10 -0
  18. package/dist/{DataTable-BMRU8a1j.d.ts → DataTable-2N_tqbfq.d.ts} +1 -1
  19. package/dist/DataTable-LRJL4IRV.js +15 -0
  20. package/dist/{PublicPageProvider-DEMpysFR.d.ts → PublicPageProvider-BBH6Vqg7.d.ts} +72 -139
  21. package/dist/UnifiedAuthProvider-ZT6TIGM7.js +7 -0
  22. package/dist/api-Y4MQWOFW.js +4 -0
  23. package/dist/audit-MYQXYZFU.js +3 -0
  24. package/dist/{chunk-J36DSWQK.js → chunk-2HGJFNAH.js} +8 -28
  25. package/dist/{chunk-OEWDTMG7.js → chunk-3O3WHILE.js} +38 -121
  26. package/dist/{chunk-M43Y4SSO.js → chunk-3QC3KRHK.js} +1 -14
  27. package/dist/{chunk-DGUM43GV.js → chunk-3RG5ZIWI.js} +1 -4
  28. package/dist/{chunk-QXHPKYJV.js → chunk-4SXLQIZO.js} +1 -26
  29. package/dist/chunk-4T7OBVTU.js +62 -0
  30. package/dist/{chunk-E66EQZE6.js → chunk-6GLLNA6U.js} +3 -9
  31. package/dist/{chunk-ZSAAAMVR.js → chunk-6QYDGKQY.js} +1 -4
  32. package/dist/{chunk-NN6WWZ5U.js → chunk-7TYHROIV.js} +579 -563
  33. package/dist/{chunk-M7MPQISP.js → chunk-A55DK444.js} +9 -16
  34. package/dist/{chunk-63FOKYGO.js → chunk-AHU7G2R5.js} +2 -11
  35. package/dist/{chunk-L4OXEN46.js → chunk-BVP2BCJF.js} +2 -16
  36. package/dist/chunk-C7NSAPTL.js +1 -0
  37. package/dist/{chunk-YKRAFF5K.js → chunk-FENMYN2U.js} +73 -149
  38. package/dist/{chunk-AVMLPIM7.js → chunk-FTCRZOG2.js} +284 -432
  39. package/dist/{chunk-G37KK66H.js → chunk-FYHN4DD5.js} +60 -19
  40. package/dist/{chunk-VBXEHIUJ.js → chunk-HF6O3O37.js} +6 -88
  41. package/dist/{chunk-I6DAQMWX.js → chunk-LAZMKTTF.js} +930 -891
  42. package/dist/{chunk-5EC5MEWX.js → chunk-MAGBIDNS.js} +77 -222
  43. package/dist/chunk-MBADTM7L.js +64 -0
  44. package/dist/chunk-OHIK3MIO.js +994 -0
  45. package/dist/{chunk-6SOIHG6Z.js → chunk-S7DKJPLT.js} +115 -44
  46. package/dist/{chunk-FMUCXFII.js → chunk-SD6WQY43.js} +1 -5
  47. package/dist/{chunk-PWLANIRT.js → chunk-TTRFSOKR.js} +1 -7
  48. package/dist/{chunk-5DRSZLL2.js → chunk-UH3NTO3F.js} +1 -6
  49. package/dist/{chunk-FFQEQTNW.js → chunk-UIYSCEV7.js} +134 -45
  50. package/dist/{chunk-3LPHPB62.js → chunk-ZFYPMX46.js} +271 -87
  51. package/dist/{chunk-7JPAB3T5.js → chunk-ZS5VO5JB.js} +1989 -1283
  52. package/dist/components.d.ts +6 -6
  53. package/dist/components.js +57 -267
  54. package/dist/{database.generated-CzIvgcPu.d.ts → database.generated-CcnC_DRc.d.ts} +4795 -3691
  55. package/dist/eslint-rules/index.cjs +22 -0
  56. package/dist/eslint-rules/rules/compliance.cjs +348 -0
  57. package/dist/eslint-rules/rules/components.cjs +113 -0
  58. package/dist/eslint-rules/rules/imports.cjs +102 -0
  59. package/dist/eslint-rules/rules/rbac.cjs +790 -0
  60. package/dist/eslint-rules/utils/helpers.cjs +42 -0
  61. package/dist/eslint-rules/utils/manifest-loader.cjs +75 -0
  62. package/dist/hooks.d.ts +5 -5
  63. package/dist/hooks.js +62 -270
  64. package/dist/icons/index.d.ts +1 -0
  65. package/dist/icons/index.js +1 -0
  66. package/dist/index.d.ts +36 -26
  67. package/dist/index.js +87 -690
  68. package/dist/providers.d.ts +2 -2
  69. package/dist/providers.js +8 -35
  70. package/dist/rbac/eslint-rules.d.ts +46 -44
  71. package/dist/rbac/eslint-rules.js +7 -4
  72. package/dist/rbac/index.d.ts +124 -594
  73. package/dist/rbac/index.js +14 -207
  74. package/dist/styles/index.js +2 -12
  75. package/dist/theming/runtime.js +3 -19
  76. package/dist/{timezone-CHhWg6b4.d.ts → timezone-BZe_eUxx.d.ts} +175 -1
  77. package/dist/{types-CkbwOr4Y.d.ts → types-B-K_5VnO.d.ts} +4 -0
  78. package/dist/types-t9H8qKRw.d.ts +55 -0
  79. package/dist/types.d.ts +1 -1
  80. package/dist/types.js +7 -94
  81. package/dist/{usePublicRouteParams-i3qtoBgg.d.ts → usePublicRouteParams-COZ28Mvq.d.ts} +9 -9
  82. package/dist/utils.d.ts +24 -117
  83. package/dist/utils.js +54 -392
  84. package/docs/README.md +16 -6
  85. package/docs/api/README.md +4 -402
  86. package/docs/api/modules.md +454 -930
  87. package/docs/api-reference/components.md +3 -1
  88. package/docs/api-reference/deprecated.md +31 -6
  89. package/docs/api-reference/rpc-functions.md +78 -3
  90. package/docs/best-practices/accessibility.md +6 -3
  91. package/docs/getting-started/cursor-rules.md +3 -23
  92. package/docs/getting-started/dependencies.md +650 -0
  93. package/docs/getting-started/installation-guide.md +20 -7
  94. package/docs/getting-started/quick-start.md +23 -12
  95. package/docs/implementation-guides/permission-enforcement.md +4 -0
  96. package/docs/rbac/MIGRATION_GUIDE.md +819 -0
  97. package/docs/rbac/RBAC_CONTRACT.md +724 -0
  98. package/docs/rbac/README.md +12 -3
  99. package/docs/rbac/edge-functions-guide.md +376 -0
  100. package/docs/rbac/secure-client-protection.md +0 -34
  101. package/docs/standards/00-pace-core-compliance.md +967 -0
  102. package/docs/standards/01-standards-compliance.md +188 -0
  103. package/docs/standards/02-project-structure.md +985 -0
  104. package/docs/standards/03-solid-principles.md +39 -0
  105. package/docs/standards/04-testing-standards.md +36 -0
  106. package/docs/standards/05-bug-reports-and-features.md +27 -0
  107. package/docs/standards/{04-code-style-standard.md → 06-code-quality.md} +2 -0
  108. package/docs/standards/07-tech-stack-compliance.md +30 -0
  109. package/docs/standards/08-markup-quality.md +345 -0
  110. package/docs/standards/{07-rbac-and-rls-standard.md → 09-rbac-compliance.md} +149 -54
  111. package/docs/standards/10-error-handling-patterns.md +401 -0
  112. package/docs/standards/11-performance-optimization.md +348 -0
  113. package/docs/standards/12-ci-cd-integration.md +370 -0
  114. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +192 -0
  115. package/docs/standards/README.md +62 -33
  116. package/docs/troubleshooting/organisation-context-setup.md +42 -19
  117. package/eslint-config-pace-core.cjs +20 -4
  118. package/package.json +31 -21
  119. package/scripts/audit/audit-compliance.cjs +1295 -0
  120. package/scripts/audit/audit-components.cjs +260 -0
  121. package/scripts/audit/audit-dependencies.cjs +395 -0
  122. package/scripts/audit/audit-rbac.cjs +954 -0
  123. package/scripts/audit/audit-standards.cjs +1268 -0
  124. package/scripts/audit/index.cjs +1898 -194
  125. package/scripts/install-cursor-rules.cjs +259 -8
  126. package/scripts/validate-master.js +1 -1
  127. package/src/__tests__/fixtures/supabase.ts +1 -1
  128. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +1 -1
  129. package/src/__tests__/helpers/__tests__/optimized-test-setup.test.ts +1 -1
  130. package/src/__tests__/helpers/__tests__/supabaseMock.test.ts +1 -1
  131. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +3 -3
  132. package/src/__tests__/helpers/component-test-utils.tsx +1 -1
  133. package/src/__tests__/helpers/supabaseMock.ts +2 -2
  134. package/src/__tests__/public-recipe-view.test.ts +38 -9
  135. package/src/components/Button/Button.tsx +5 -1
  136. package/src/components/ContextSelector/ContextSelector.tsx +42 -39
  137. package/src/components/DataTable/__tests__/keyboard.test.tsx +15 -2
  138. package/src/components/DataTable/components/DataTableBody.tsx +55 -31
  139. package/src/components/DataTable/components/DataTableCore.tsx +186 -13
  140. package/src/components/DataTable/components/DataTableLayout.tsx +30 -5
  141. package/src/components/DataTable/components/EditFields.tsx +23 -3
  142. package/src/components/DataTable/components/EditableRow.tsx +7 -2
  143. package/src/components/DataTable/components/ImportModal.tsx +4 -6
  144. package/src/components/DataTable/components/RowComponent.tsx +12 -0
  145. package/src/components/DataTable/components/ViewRowModal.tsx +4 -4
  146. package/src/components/DataTable/components/__tests__/ImportModal.test.tsx +455 -96
  147. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +122 -58
  148. package/src/components/DataTable/components/hooks/usePermissionTracking.ts +0 -4
  149. package/src/components/DataTable/core/DataTableContext.tsx +1 -1
  150. package/src/components/DataTable/hooks/__tests__/useDataTableState.test.ts +51 -47
  151. package/src/components/DataTable/hooks/useDataTablePermissions.ts +24 -21
  152. package/src/components/DataTable/hooks/useDataTableState.ts +125 -9
  153. package/src/components/DataTable/hooks/useTableColumns.ts +40 -2
  154. package/src/components/DataTable/hooks/useTableHandlers.ts +11 -0
  155. package/src/components/DataTable/types.ts +5 -0
  156. package/src/components/DateTimeField/DateTimeField.tsx +20 -20
  157. package/src/components/DateTimeField/README.md +5 -2
  158. package/src/components/Dialog/Dialog.test.tsx +361 -318
  159. package/src/components/Dialog/Dialog.tsx +1154 -323
  160. package/src/components/Dialog/index.ts +3 -3
  161. package/src/components/FileDisplay/FileDisplay.test.tsx +45 -2
  162. package/src/components/FileDisplay/FileDisplay.tsx +28 -22
  163. package/src/components/Form/Form.test.tsx +9 -10
  164. package/src/components/Form/Form.tsx +369 -9
  165. package/src/components/InactivityWarningModal/InactivityWarningModal.test.tsx +28 -28
  166. package/src/components/InactivityWarningModal/InactivityWarningModal.tsx +40 -54
  167. package/src/components/LoginForm/LoginForm.tsx +2 -2
  168. package/src/components/NavigationMenu/NavigationMenu.test.tsx +14 -13
  169. package/src/components/NavigationMenu/NavigationMenu.tsx +2 -2
  170. package/src/components/NavigationMenu/useNavigationFiltering.ts +11 -21
  171. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +6 -4
  172. package/src/components/PaceAppLayout/PaceAppLayout.tsx +30 -41
  173. package/src/components/PaceAppLayout/README.md +10 -9
  174. package/src/components/PaceAppLayout/test-setup.tsx +40 -31
  175. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +108 -61
  176. package/src/components/PaceLoginPage/PaceLoginPage.tsx +27 -3
  177. package/src/components/PasswordChange/PasswordChangeForm.test.tsx +61 -0
  178. package/src/components/PasswordChange/PasswordChangeForm.tsx +20 -13
  179. package/src/components/PublicLayout/PublicLayout.test.tsx +7 -3
  180. package/src/components/PublicLayout/PublicPageLayout.tsx +5 -8
  181. package/src/components/Select/Select.tsx +23 -21
  182. package/src/components/Select/types.ts +1 -1
  183. package/src/components/UserMenu/UserMenu.test.tsx +38 -6
  184. package/src/components/UserMenu/UserMenu.tsx +39 -34
  185. package/src/components/index.ts +3 -4
  186. package/src/eslint-rules/index.cjs +22 -0
  187. package/src/eslint-rules/rules/compliance.cjs +348 -0
  188. package/src/eslint-rules/rules/components.cjs +113 -0
  189. package/src/eslint-rules/rules/imports.cjs +102 -0
  190. package/src/eslint-rules/rules/rbac.cjs +790 -0
  191. package/src/eslint-rules/utils/helpers.cjs +42 -0
  192. package/src/eslint-rules/utils/manifest-loader.cjs +75 -0
  193. package/src/hooks/__tests__/hooks.integration.test.tsx +6 -8
  194. package/src/hooks/__tests__/useAppConfig.unit.test.ts +129 -67
  195. package/src/hooks/__tests__/usePublicEvent.simple.test.ts +149 -67
  196. package/src/hooks/__tests__/usePublicEvent.test.ts +149 -79
  197. package/src/hooks/__tests__/usePublicEvent.unit.test.ts +158 -109
  198. package/src/hooks/__tests__/useSessionDraft.test.ts +163 -0
  199. package/src/hooks/__tests__/useSessionRestoration.unit.test.tsx +10 -5
  200. package/src/hooks/public/usePublicEvent.ts +62 -190
  201. package/src/hooks/public/usePublicEventLogo.test.ts +70 -17
  202. package/src/hooks/public/usePublicEventLogo.ts +19 -9
  203. package/src/hooks/useAppConfig.ts +26 -24
  204. package/src/hooks/useEventTheme.test.ts +211 -233
  205. package/src/hooks/useEventTheme.ts +19 -28
  206. package/src/hooks/useEvents.ts +11 -7
  207. package/src/hooks/useKeyboardShortcuts.ts +1 -1
  208. package/src/hooks/useOrganisationPermissions.ts +9 -11
  209. package/src/hooks/useOrganisations.ts +13 -7
  210. package/src/hooks/useQueryCache.ts +0 -1
  211. package/src/hooks/useSessionDraft.ts +380 -0
  212. package/src/hooks/useSessionRestoration.ts +3 -1
  213. package/src/icons/index.ts +27 -0
  214. package/src/index.ts +16 -1
  215. package/src/providers/OrganisationProvider.tsx +23 -14
  216. package/src/providers/services/EventServiceProvider.tsx +1 -24
  217. package/src/providers/services/UnifiedAuthProvider.tsx +5 -48
  218. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +3 -0
  219. package/src/rbac/README.md +20 -20
  220. package/src/rbac/__tests__/adapters.comprehensive.test.tsx +7 -457
  221. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +33 -7
  222. package/src/rbac/adapters.tsx +7 -295
  223. package/src/rbac/api.test.ts +44 -56
  224. package/src/rbac/api.ts +10 -17
  225. package/src/rbac/cache-invalidation.ts +0 -1
  226. package/src/rbac/compliance/index.ts +10 -0
  227. package/src/rbac/compliance/pattern-detector.ts +553 -0
  228. package/src/rbac/compliance/runtime-compliance.ts +22 -0
  229. package/src/rbac/components/AccessDenied.tsx +150 -0
  230. package/src/rbac/components/NavigationGuard.tsx +12 -20
  231. package/src/rbac/components/PagePermissionGuard.tsx +4 -24
  232. package/src/rbac/components/__tests__/NavigationGuard.test.tsx +21 -8
  233. package/src/rbac/components/index.ts +3 -41
  234. package/src/rbac/eslint-rules.js +1 -1
  235. package/src/rbac/hooks/index.ts +0 -3
  236. package/src/rbac/hooks/permissions/index.ts +0 -3
  237. package/src/rbac/hooks/permissions/useAccessLevel.ts +4 -8
  238. package/src/rbac/hooks/usePermissions.ts +0 -3
  239. package/src/rbac/hooks/useRBAC.test.ts +21 -3
  240. package/src/rbac/hooks/useRBAC.ts +4 -3
  241. package/src/rbac/hooks/useResolvedScope.test.ts +57 -47
  242. package/src/rbac/hooks/useResolvedScope.ts +58 -140
  243. package/src/rbac/hooks/useResourcePermissions.test.ts +241 -60
  244. package/src/rbac/hooks/useResourcePermissions.ts +182 -63
  245. package/src/rbac/hooks/useRoleManagement.test.ts +65 -22
  246. package/src/rbac/hooks/useRoleManagement.ts +147 -19
  247. package/src/rbac/hooks/useSecureSupabase.ts +4 -8
  248. package/src/rbac/index.ts +7 -9
  249. package/src/rbac/permissions.ts +17 -17
  250. package/src/rbac/utils/contextValidator.ts +45 -7
  251. package/src/services/AuthService.ts +132 -23
  252. package/src/services/EventService.ts +4 -97
  253. package/src/services/InactivityService.ts +155 -58
  254. package/src/services/OrganisationService.ts +7 -44
  255. package/src/services/__tests__/OrganisationService.test.ts +26 -8
  256. package/src/services/base/BaseService.ts +0 -3
  257. package/src/styles/core.css +4 -0
  258. package/src/types/database.generated.ts +4733 -3809
  259. package/src/utils/__tests__/organisationContext.unit.test.ts +9 -10
  260. package/src/utils/context/organisationContext.test.ts +13 -28
  261. package/src/utils/context/organisationContext.ts +21 -52
  262. package/src/utils/dynamic/dynamicUtils.ts +1 -1
  263. package/src/utils/file-reference/index.ts +39 -15
  264. package/src/utils/formatting/formatDateTime.test.ts +3 -2
  265. package/src/utils/formatting/formatTime.test.ts +3 -2
  266. package/src/utils/google-places/loadGoogleMapsScript.ts +29 -4
  267. package/src/utils/index.ts +4 -1
  268. package/src/utils/persistence/__tests__/keyDerivation.test.ts +135 -0
  269. package/src/utils/persistence/__tests__/sensitiveFieldDetection.test.ts +123 -0
  270. package/src/utils/persistence/keyDerivation.ts +304 -0
  271. package/src/utils/persistence/sensitiveFieldDetection.ts +212 -0
  272. package/src/utils/security/secureStorage.ts +5 -5
  273. package/src/utils/storage/helpers.ts +3 -3
  274. package/src/utils/supabase/createBaseClient.ts +147 -0
  275. package/src/utils/timezone/timezone.test.ts +1 -2
  276. package/src/utils/timezone/timezone.ts +1 -1
  277. package/src/utils/validation/csrf.ts +4 -4
  278. package/cursor-rules/CHANGELOG.md +0 -119
  279. package/cursor-rules/README.md +0 -192
  280. package/dist/DataTable-E7YQZD7D.js +0 -175
  281. package/dist/DataTable-E7YQZD7D.js.map +0 -1
  282. package/dist/UnifiedAuthProvider-QPXO24B4.js +0 -18
  283. package/dist/UnifiedAuthProvider-QPXO24B4.js.map +0 -1
  284. package/dist/api-6LVZTHDS.js +0 -52
  285. package/dist/api-6LVZTHDS.js.map +0 -1
  286. package/dist/audit-V53FV5AG.js +0 -17
  287. package/dist/audit-V53FV5AG.js.map +0 -1
  288. package/dist/chunk-36LVWXB2.js +0 -227
  289. package/dist/chunk-36LVWXB2.js.map +0 -1
  290. package/dist/chunk-3LPHPB62.js.map +0 -1
  291. package/dist/chunk-5DRSZLL2.js.map +0 -1
  292. package/dist/chunk-5EC5MEWX.js.map +0 -1
  293. package/dist/chunk-63FOKYGO.js.map +0 -1
  294. package/dist/chunk-6SOIHG6Z.js.map +0 -1
  295. package/dist/chunk-7JPAB3T5.js.map +0 -1
  296. package/dist/chunk-ATKZM7RX.js +0 -2053
  297. package/dist/chunk-ATKZM7RX.js.map +0 -1
  298. package/dist/chunk-AVMLPIM7.js.map +0 -1
  299. package/dist/chunk-DGUM43GV.js.map +0 -1
  300. package/dist/chunk-E66EQZE6.js.map +0 -1
  301. package/dist/chunk-FFQEQTNW.js.map +0 -1
  302. package/dist/chunk-FMUCXFII.js.map +0 -1
  303. package/dist/chunk-G37KK66H.js.map +0 -1
  304. package/dist/chunk-I6DAQMWX.js.map +0 -1
  305. package/dist/chunk-J36DSWQK.js.map +0 -1
  306. package/dist/chunk-KQCRWDSA.js +0 -1
  307. package/dist/chunk-KQCRWDSA.js.map +0 -1
  308. package/dist/chunk-L4OXEN46.js.map +0 -1
  309. package/dist/chunk-LMC26NLJ.js +0 -84
  310. package/dist/chunk-LMC26NLJ.js.map +0 -1
  311. package/dist/chunk-M43Y4SSO.js.map +0 -1
  312. package/dist/chunk-M7MPQISP.js.map +0 -1
  313. package/dist/chunk-NN6WWZ5U.js.map +0 -1
  314. package/dist/chunk-OEWDTMG7.js.map +0 -1
  315. package/dist/chunk-PWLANIRT.js.map +0 -1
  316. package/dist/chunk-QXHPKYJV.js.map +0 -1
  317. package/dist/chunk-VBXEHIUJ.js.map +0 -1
  318. package/dist/chunk-YKRAFF5K.js.map +0 -1
  319. package/dist/chunk-ZSAAAMVR.js.map +0 -1
  320. package/dist/components.js.map +0 -1
  321. package/dist/contextValidator-OOPCLPZW.js +0 -9
  322. package/dist/contextValidator-OOPCLPZW.js.map +0 -1
  323. package/dist/eslint-rules/pace-core-compliance.cjs +0 -510
  324. package/dist/hooks.js.map +0 -1
  325. package/dist/index.js.map +0 -1
  326. package/dist/providers.js.map +0 -1
  327. package/dist/rbac/eslint-rules.js.map +0 -1
  328. package/dist/rbac/index.js.map +0 -1
  329. package/dist/styles/index.js.map +0 -1
  330. package/dist/theming/runtime.js.map +0 -1
  331. package/dist/types.js.map +0 -1
  332. package/dist/utils.js.map +0 -1
  333. package/docs/standards/01-architecture-standard.md +0 -44
  334. package/docs/standards/02-api-and-rpc-standard.md +0 -39
  335. package/docs/standards/03-component-standard.md +0 -32
  336. package/docs/standards/05-security-standard.md +0 -44
  337. package/docs/standards/06-testing-and-docs-standard.md +0 -29
  338. package/docs/standards/pace-core-compliance.md +0 -432
  339. package/scripts/audit/core/checks/accessibility.cjs +0 -197
  340. package/scripts/audit/core/checks/api-usage.cjs +0 -191
  341. package/scripts/audit/core/checks/bundle.cjs +0 -142
  342. package/scripts/audit/core/checks/compliance.cjs +0 -2706
  343. package/scripts/audit/core/checks/config.cjs +0 -54
  344. package/scripts/audit/core/checks/coverage.cjs +0 -84
  345. package/scripts/audit/core/checks/dependencies.cjs +0 -994
  346. package/scripts/audit/core/checks/documentation.cjs +0 -268
  347. package/scripts/audit/core/checks/environment.cjs +0 -116
  348. package/scripts/audit/core/checks/error-handling.cjs +0 -340
  349. package/scripts/audit/core/checks/forms.cjs +0 -172
  350. package/scripts/audit/core/checks/heuristics.cjs +0 -68
  351. package/scripts/audit/core/checks/hooks.cjs +0 -334
  352. package/scripts/audit/core/checks/imports.cjs +0 -244
  353. package/scripts/audit/core/checks/performance.cjs +0 -325
  354. package/scripts/audit/core/checks/routes.cjs +0 -117
  355. package/scripts/audit/core/checks/state.cjs +0 -130
  356. package/scripts/audit/core/checks/structure.cjs +0 -65
  357. package/scripts/audit/core/checks/style.cjs +0 -584
  358. package/scripts/audit/core/checks/testing.cjs +0 -122
  359. package/scripts/audit/core/checks/typescript.cjs +0 -61
  360. package/scripts/audit/core/scanner.cjs +0 -199
  361. package/scripts/audit/core/utils.cjs +0 -137
  362. package/scripts/audit/reporters/console.cjs +0 -151
  363. package/scripts/audit/reporters/json.cjs +0 -54
  364. package/scripts/audit/reporters/markdown.cjs +0 -124
  365. package/scripts/audit-consuming-app.cjs +0 -86
  366. package/src/eslint-rules/pace-core-compliance.cjs +0 -510
  367. package/src/eslint-rules/pace-core-compliance.js +0 -638
  368. package/src/rbac/components/EnhancedNavigationMenu.test.tsx +0 -555
  369. package/src/rbac/components/EnhancedNavigationMenu.tsx +0 -293
  370. package/src/rbac/components/NavigationProvider.test.tsx +0 -481
  371. package/src/rbac/components/NavigationProvider.tsx +0 -345
  372. package/src/rbac/components/PagePermissionProvider.test.tsx +0 -476
  373. package/src/rbac/components/PagePermissionProvider.tsx +0 -279
  374. package/src/rbac/components/PermissionEnforcer.tsx +0 -312
  375. package/src/rbac/components/RoleBasedRouter.tsx +0 -440
  376. package/src/rbac/components/SecureDataProvider.test.tsx +0 -543
  377. package/src/rbac/components/SecureDataProvider.tsx +0 -339
  378. package/src/rbac/components/__tests__/EnhancedNavigationMenu.test.tsx +0 -620
  379. package/src/rbac/components/__tests__/NavigationProvider.test.tsx +0 -726
  380. package/src/rbac/components/__tests__/PagePermissionProvider.test.tsx +0 -661
  381. package/src/rbac/components/__tests__/PermissionEnforcer.test.tsx +0 -881
  382. package/src/rbac/components/__tests__/RoleBasedRouter.test.tsx +0 -783
  383. package/src/rbac/components/__tests__/SecureDataProvider.fixed.test.tsx +0 -645
  384. package/src/rbac/components/__tests__/SecureDataProvider.test.tsx +0 -659
  385. package/src/rbac/hooks/permissions/useCachedPermissions.ts +0 -79
  386. package/src/rbac/hooks/permissions/useHasAllPermissions.ts +0 -90
  387. package/src/rbac/hooks/permissions/useHasAnyPermission.ts +0 -90
@@ -205,6 +205,14 @@ export class InactivityService extends BaseService implements IInactivityService
205
205
  logger.error('InactivityService', 'Error during idle logout:', error);
206
206
  }
207
207
 
208
+ // Clear sessionStorage on logout
209
+ try {
210
+ sessionStorage.clear();
211
+ } catch (storageError) {
212
+ // Ignore storage errors (e.g., in private browsing mode)
213
+ logger.warn('InactivityService', 'Failed to clear sessionStorage', { error: storageError });
214
+ }
215
+
208
216
  // Call app callback for navigation/redirect
209
217
  this.onIdleLogout?.('inactivity');
210
218
  this.notify();
@@ -231,6 +239,14 @@ export class InactivityService extends BaseService implements IInactivityService
231
239
  logger.error('InactivityService', 'Error during manual sign out:', error);
232
240
  }
233
241
 
242
+ // Clear sessionStorage on logout
243
+ try {
244
+ sessionStorage.clear();
245
+ } catch (storageError) {
246
+ // Ignore storage errors (e.g., in private browsing mode)
247
+ logger.warn('InactivityService', 'Failed to clear sessionStorage', { error: storageError });
248
+ }
249
+
234
250
  // Call app callback for navigation/redirect
235
251
  this.onIdleLogout?.('inactivity');
236
252
  this.notify();
@@ -291,10 +307,10 @@ export class InactivityService extends BaseService implements IInactivityService
291
307
  private setupEventHandlers(): void {
292
308
  if (typeof window === 'undefined') return;
293
309
 
294
- let idleTimer: NodeJS.Timeout | null = null;
295
310
  let warningTimer: NodeJS.Timeout | null = null;
311
+ let logoutTimer: NodeJS.Timeout | null = null;
312
+ let countdownInterval: NodeJS.Timeout | null = null;
296
313
  let lastActivity = Date.now();
297
- let pollInterval: NodeJS.Timeout | null = null;
298
314
 
299
315
  // Store previous state for comparison
300
316
  let prevIsIdle = false;
@@ -303,19 +319,29 @@ export class InactivityService extends BaseService implements IInactivityService
303
319
  let prevInactivityTimeRemaining = 0;
304
320
  let prevTimeRemaining = this.idleTimeoutMs;
305
321
 
306
- // Poll every 10 seconds to check for state changes
307
- const pollInactivityState = () => {
322
+ // Calculate time until warning and logout
323
+ const getTimeUntilWarning = () => {
324
+ const timeSinceActivity = Date.now() - lastActivity;
325
+ return Math.max(0, (this.idleTimeoutMs - this.warnBeforeMs) - timeSinceActivity);
326
+ };
327
+
328
+ const getTimeUntilLogout = () => {
329
+ const timeSinceActivity = Date.now() - lastActivity;
330
+ return Math.max(0, this.idleTimeoutMs - timeSinceActivity);
331
+ };
332
+
333
+ // Update state and notify if changed
334
+ const updateState = (forceNotify = false) => {
308
335
  const now = Date.now();
309
336
  const timeSinceActivity = now - lastActivity;
310
337
  const timeUntilIdle = this.idleTimeoutMs - timeSinceActivity;
311
- const timeUntilWarning = (this.idleTimeoutMs - this.warnBeforeMs) - timeSinceActivity;
312
338
 
313
- // Calculate new state values based on time since last activity
314
- const newIsIdle = timeSinceActivity >= (this.idleTimeoutMs - this.warnBeforeMs);
315
- const newShowWarning = newIsIdle && timeSinceActivity < this.idleTimeoutMs;
339
+ // Calculate new state values
340
+ const newIsIdle = timeSinceActivity >= this.idleTimeoutMs;
341
+ const newShowWarning = timeSinceActivity >= (this.idleTimeoutMs - this.warnBeforeMs) && !newIsIdle;
316
342
  const newShowInactivityWarning = newShowWarning;
317
343
  const newInactivityTimeRemaining = newShowWarning
318
- ? Math.ceil((this.idleTimeoutMs - timeSinceActivity) / 1000)
344
+ ? Math.ceil(timeUntilIdle / 1000)
319
345
  : 0;
320
346
  const newTimeRemaining = Math.max(0, timeUntilIdle);
321
347
 
@@ -324,11 +350,11 @@ export class InactivityService extends BaseService implements IInactivityService
324
350
  prevIsIdle !== newIsIdle ||
325
351
  prevShowWarning !== newShowWarning ||
326
352
  prevShowInactivityWarning !== newShowInactivityWarning ||
327
- prevInactivityTimeRemaining !== newInactivityTimeRemaining ||
353
+ (newShowWarning && prevInactivityTimeRemaining !== newInactivityTimeRemaining) ||
328
354
  prevTimeRemaining !== newTimeRemaining;
329
355
 
330
- // Only update and notify if state changed
331
- if (stateChanged) {
356
+ // Only update and notify if state changed or forced
357
+ if (stateChanged || forceNotify) {
332
358
  this._isIdle = newIsIdle;
333
359
  this._showWarning = newShowWarning;
334
360
  this._showInactivityWarning = newShowInactivityWarning;
@@ -342,76 +368,147 @@ export class InactivityService extends BaseService implements IInactivityService
342
368
  prevInactivityTimeRemaining = newInactivityTimeRemaining;
343
369
  prevTimeRemaining = newTimeRemaining;
344
370
 
345
- this.notify();
371
+ if (stateChanged) {
372
+ this.notify();
373
+ }
346
374
 
347
375
  // Handle idle logout if needed
348
- if (newIsIdle && timeSinceActivity >= this.idleTimeoutMs) {
376
+ if (newIsIdle) {
349
377
  this.handleIdleLogout();
350
378
  }
351
379
  }
352
-
353
- // Update timers based on current state
354
- if (idleTimer) {
355
- clearTimeout(idleTimer);
356
- idleTimer = null;
357
- }
358
-
380
+ };
381
+
382
+ // Schedule next state check based on current state
383
+ const scheduleNextCheck = () => {
384
+ // Clear existing timers
359
385
  if (warningTimer) {
360
386
  clearTimeout(warningTimer);
361
387
  warningTimer = null;
362
388
  }
363
389
 
364
- // Set up timers for next state transitions
365
- if (!newIsIdle && timeUntilIdle > 0) {
366
- idleTimer = setTimeout(() => {
367
- pollInactivityState();
368
- }, Math.min(10000, timeUntilIdle));
390
+ if (logoutTimer) {
391
+ clearTimeout(logoutTimer);
392
+ logoutTimer = null;
369
393
  }
370
394
 
371
- if (newShowWarning && timeUntilIdle > 0) {
372
- warningTimer = setTimeout(() => {
395
+ if (countdownInterval) {
396
+ clearInterval(countdownInterval);
397
+ countdownInterval = null;
398
+ }
399
+
400
+ const timeUntilWarning = getTimeUntilWarning();
401
+ const timeUntilLogout = getTimeUntilLogout();
402
+ const timeSinceActivity = Date.now() - lastActivity;
403
+
404
+ // If already idle, nothing to schedule
405
+ if (timeSinceActivity >= this.idleTimeoutMs) {
406
+ return;
407
+ }
408
+
409
+ // If warning should be shown, start countdown interval
410
+ if (timeSinceActivity >= (this.idleTimeoutMs - this.warnBeforeMs)) {
411
+ // Update state to show warning
412
+ updateState();
413
+
414
+ // Start countdown interval to update remaining time every second
415
+ countdownInterval = setInterval(() => {
416
+ updateState();
417
+
418
+ // Check if we've reached logout time
419
+ if (Date.now() - lastActivity >= this.idleTimeoutMs) {
420
+ if (countdownInterval) {
421
+ clearInterval(countdownInterval);
422
+ countdownInterval = null;
423
+ }
424
+ this.handleIdleLogout();
425
+ }
426
+ }, 1000); // Update every second during warning period
427
+
428
+ // Schedule logout
429
+ logoutTimer = setTimeout(() => {
430
+ if (countdownInterval) {
431
+ clearInterval(countdownInterval);
432
+ countdownInterval = null;
433
+ }
373
434
  this.handleIdleLogout();
374
- }, timeUntilIdle);
435
+ }, timeUntilLogout);
436
+ } else {
437
+ // User is still active - schedule warning timer
438
+ // Use adaptive interval: check more frequently as we approach warning time
439
+ // Check every 60 seconds when far from warning, every 10 seconds when close
440
+ const timeUntilWarningMs = timeUntilWarning;
441
+ const adaptiveInterval = timeUntilWarningMs > 5 * 60 * 1000
442
+ ? 60 * 1000 // Check every 60 seconds when > 5 minutes away
443
+ : timeUntilWarningMs > 60 * 1000
444
+ ? 10 * 1000 // Check every 10 seconds when < 5 minutes but > 1 minute away
445
+ : 1000; // Check every second when < 1 minute away
446
+
447
+ warningTimer = setTimeout(() => {
448
+ updateState();
449
+ scheduleNextCheck(); // Reschedule for next check
450
+ }, Math.min(adaptiveInterval, timeUntilWarningMs));
375
451
  }
376
452
  };
377
453
 
378
454
  const resetTimers = () => {
379
- // Only update lastActivity - don't notify yet
455
+ // Update last activity time
380
456
  lastActivity = Date.now();
381
457
 
382
- // Clear timers
383
- if (idleTimer) {
384
- clearTimeout(idleTimer);
385
- idleTimer = null;
386
- }
387
-
458
+ // Clear all timers
388
459
  if (warningTimer) {
389
460
  clearTimeout(warningTimer);
390
461
  warningTimer = null;
391
462
  }
392
463
 
393
- // Reset state values (will be checked on next poll)
464
+ if (logoutTimer) {
465
+ clearTimeout(logoutTimer);
466
+ logoutTimer = null;
467
+ }
468
+
469
+ if (countdownInterval) {
470
+ clearInterval(countdownInterval);
471
+ countdownInterval = null;
472
+ }
473
+
474
+ // Reset state values
475
+ const hadWarning = this._showWarning || this._showInactivityWarning;
394
476
  this._showInactivityWarning = false;
395
477
  this._inactivityTimeRemaining = 0;
396
478
  this._isIdle = false;
397
479
  this._showWarning = false;
480
+ this._timeRemaining = this.idleTimeoutMs;
398
481
 
399
- // Update previous state to match
482
+ // Update previous state
400
483
  prevIsIdle = false;
401
484
  prevShowWarning = false;
402
485
  prevShowInactivityWarning = false;
403
486
  prevInactivityTimeRemaining = 0;
404
487
  prevTimeRemaining = this.idleTimeoutMs;
405
488
 
406
- // Poll will check and notify if needed
489
+ // Notify if we were showing a warning (state changed)
490
+ if (hadWarning) {
491
+ this.notify();
492
+ }
493
+
494
+ // Reschedule next check
495
+ scheduleNextCheck();
407
496
  };
408
497
 
409
- // Activity detection - only updates lastActivity, doesn't notify
498
+ // Activity detection - throttled to avoid excessive calls
410
499
  const activityEvents = ['mousedown', 'mousemove', 'keypress', 'scroll', 'touchstart', 'click'];
500
+ let activityThrottleTimer: NodeJS.Timeout | null = null;
411
501
 
412
502
  const handleActivity = () => {
413
- resetTimers();
414
- // Don't call notify - polling will handle state updates
503
+ // Throttle activity detection to once per second max
504
+ if (activityThrottleTimer) {
505
+ return;
506
+ }
507
+
508
+ activityThrottleTimer = setTimeout(() => {
509
+ activityThrottleTimer = null;
510
+ resetTimers();
511
+ }, 1000);
415
512
  };
416
513
 
417
514
  // Add event listeners
@@ -419,29 +516,30 @@ export class InactivityService extends BaseService implements IInactivityService
419
516
  document.addEventListener(event, handleActivity, true);
420
517
  });
421
518
 
422
- // Start polling every 10 seconds
423
- pollInterval = setInterval(() => {
424
- pollInactivityState();
425
- }, 10000); // 10 seconds
426
-
427
- // Initial poll
428
- pollInactivityState();
519
+ // Initial state update and schedule first check
520
+ updateState(true); // Force initial notification
521
+ scheduleNextCheck();
429
522
 
430
523
  // Store cleanup function
431
524
  this.cleanupHandlers = () => {
432
- if (idleTimer) {
433
- clearTimeout(idleTimer);
434
- idleTimer = null;
435
- }
436
-
437
525
  if (warningTimer) {
438
526
  clearTimeout(warningTimer);
439
527
  warningTimer = null;
440
528
  }
441
529
 
442
- if (pollInterval) {
443
- clearInterval(pollInterval);
444
- pollInterval = null;
530
+ if (logoutTimer) {
531
+ clearTimeout(logoutTimer);
532
+ logoutTimer = null;
533
+ }
534
+
535
+ if (countdownInterval) {
536
+ clearInterval(countdownInterval);
537
+ countdownInterval = null;
538
+ }
539
+
540
+ if (activityThrottleTimer) {
541
+ clearTimeout(activityThrottleTimer);
542
+ activityThrottleTimer = null;
445
543
  }
446
544
 
447
545
  activityEvents.forEach(event => {
@@ -457,6 +555,5 @@ export class InactivityService extends BaseService implements IInactivityService
457
555
  };
458
556
 
459
557
  this._isTracking = true;
460
- this.notify(); // Initial notification only
461
558
  }
462
559
  }
@@ -70,10 +70,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
70
70
  this.supabaseClient = supabaseClient;
71
71
  this.user = user;
72
72
  this.session = session;
73
- logger.debug('OrganisationService', `Instance created [ID:${this.instanceId}]`, {
74
- hasUser: !!user,
75
- userId: user?.id
76
- });
77
73
  }
78
74
 
79
75
  getInstanceId(): number {
@@ -164,10 +160,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
164
160
 
165
161
  if (userChanged || needsRetry || isEmpty) {
166
162
  if (userChanged) {
167
- logger.debug('OrganisationService', `User changed [ID:${this.instanceId}], resetting initialization`, {
168
- previousUserId,
169
- newUserId
170
- });
171
163
  } else if (needsRetry) {
172
164
  logger.debug('OrganisationService', `Previous error detected [ID:${this.instanceId}], retrying initialization`);
173
165
  } else if (isEmpty) {
@@ -293,7 +285,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
293
285
  // SECURITY: Only initialize if we have an authenticated user
294
286
  // This prevents premature initialization during early auth states
295
287
  if (!this.user) {
296
- logger.debug('OrganisationService', 'Skipping initialization - no user');
297
288
  return;
298
289
  }
299
290
 
@@ -337,34 +328,13 @@ export class OrganisationService extends BaseService implements IOrganisationSer
337
328
  }
338
329
 
339
330
  private async setDatabaseOrganisationContext(organisation: Organisation): Promise<void> {
340
- if (!this.supabaseClient || !this.session) {
341
- logger.warn('OrganisationService', 'No Supabase client or session available for setting organisation context');
342
- this._isContextReady = false;
343
- this.notify();
344
- return;
345
- }
346
-
347
- try {
348
- // Add timeout to prevent hanging
349
- const timeoutPromise = new Promise((_, reject) => {
350
- setTimeout(() => reject(new Error('Context setting timeout after 5 seconds')), 5000);
351
- });
352
-
353
- const contextPromise = setOrganisationContext(this.supabaseClient, organisation.id);
354
-
355
- await Promise.race([contextPromise, timeoutPromise]);
356
-
357
- // Database organisation context set successfully
358
- this._isContextReady = true;
359
- this.notify();
360
- } catch (error) {
361
- logger.error('OrganisationService', 'Failed to set database organisation context:', error);
362
- // Set context ready to true anyway - this is a non-critical operation
363
- // The app should still work without database context
364
- this._isContextReady = true;
365
- this.notify();
366
- // Don't throw - this is a non-critical operation
367
- }
331
+ // Organisation context is now handled via secure client and explicit parameters
332
+ // This function is kept for backward compatibility but is effectively a no-op
333
+ // The setOrganisationContext function has been deprecated and no longer sets database context
334
+
335
+ // Mark context as ready immediately since context is handled elsewhere
336
+ this._isContextReady = true;
337
+ this.notify();
368
338
  }
369
339
 
370
340
  private async loadUserOrganisations(): Promise<void> {
@@ -416,9 +386,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
416
386
  this._error = null;
417
387
  this.notify();
418
388
 
419
- logger.debug('OrganisationService', 'Loading organisations for user', {
420
- userId: this.user.id
421
- });
422
389
 
423
390
  try {
424
391
  // Get user's organisation roles directly from rbac_organisation_roles table
@@ -500,10 +467,6 @@ export class OrganisationService extends BaseService implements IOrganisationSer
500
467
 
501
468
  organisations = Array.from(organisationsMap.values());
502
469
 
503
- logger.debug('OrganisationService', 'Query results', {
504
- membershipsCount: memberships.length,
505
- organisationsCount: organisations.length
506
- });
507
470
 
508
471
  // Extract organisations from join results
509
472
  } catch (queryError) {
@@ -866,10 +866,19 @@ describe('OrganisationService', () => {
866
866
  mockSession
867
867
  );
868
868
 
869
- serviceWithoutClient.setSelectedOrganisation(mockOrganisation);
870
-
871
- // Should handle gracefully
872
- await new Promise(resolve => setTimeout(resolve, 100));
869
+ // Initially context is not ready
870
+ expect(serviceWithoutClient.isContextReady()).toBe(false);
871
+
872
+ // setSelectedOrganisation requires a valid organisation in the organisations list
873
+ // Since we don't have a client, we can't load organisations, so this will throw
874
+ // or the organisation won't be in the list. The context ready state should remain false.
875
+ try {
876
+ await serviceWithoutClient.switchOrganisation(mockOrganisation.id);
877
+ } catch {
878
+ // Expected to fail
879
+ }
880
+
881
+ // Context should still be false since organisation switch failed
873
882
  expect(serviceWithoutClient.isContextReady()).toBe(false);
874
883
  });
875
884
 
@@ -880,10 +889,19 @@ describe('OrganisationService', () => {
880
889
  null
881
890
  );
882
891
 
883
- serviceWithoutSession.setSelectedOrganisation(mockOrganisation);
884
-
885
- // Should handle gracefully
886
- await new Promise(resolve => setTimeout(resolve, 100));
892
+ // Initially context is not ready
893
+ expect(serviceWithoutSession.isContextReady()).toBe(false);
894
+
895
+ // Without a session, loadUserOrganisations will return early and not load organisations
896
+ // So setSelectedOrganisation will fail because the organisation isn't in the list
897
+ // The context ready state should remain false
898
+ try {
899
+ await serviceWithoutSession.switchOrganisation(mockOrganisation.id);
900
+ } catch {
901
+ // Expected to fail
902
+ }
903
+
904
+ // Context should still be false since organisation switch failed
887
905
  expect(serviceWithoutSession.isContextReady()).toBe(false);
888
906
  });
889
907
  });
@@ -38,9 +38,6 @@ export abstract class BaseService {
38
38
  * This triggers React re-renders
39
39
  */
40
40
  protected notify(): void {
41
- const serviceName = this.constructor.name;
42
- const instanceId = (this as any).instanceId || 'unknown';
43
- logger.debug('BaseService', `[${serviceName} ID:${instanceId}] Notifying ${this.subscribers.length} subscribers`);
44
41
  this.subscribers.forEach(callback => {
45
42
  try {
46
43
  callback();
@@ -202,6 +202,10 @@
202
202
  font-size: 0.875em;
203
203
  color: var(--color-main-600);
204
204
  }
205
+
206
+ dialog::backdrop {
207
+ background-color: oklch(from var(--color-main-700) l c h / 0.5);
208
+ }
205
209
 
206
210
  .appGradient {
207
211
  background: linear-gradient(145deg, var(--color-main-100) 10%, var(--color-main-200) 30%, var(--color-main-200) 70%, var(--color-main-300) 90%);