@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
@@ -1,940 +0,0 @@
1
- ---
2
- lastUpdated: 2025-11-18T17:00:00+11:00
3
- version: 0.5.181
4
- reviewedBy: documentation-standards-audit
5
- ---
6
-
7
- # Security Best Practices
8
-
9
- Security is a critical aspect of any application. This guide provides comprehensive security best practices for using `@jmruthers/pace-core` in your applications.
10
-
11
- ## Overview
12
-
13
- The security model in `@jmruthers/pace-core` is built on several layers:
14
-
15
- - **Authentication**: Secure user authentication with Supabase
16
- - **Authorization**: Role-based access control (RBAC)
17
- - **Data Isolation**: Organisation-level data separation
18
- - **Input Validation**: Comprehensive input sanitization
19
- - **CSRF Protection**: Cross-site request forgery prevention
20
- - **XSS Prevention**: Cross-site scripting protection
21
-
22
- ## Authentication Security
23
-
24
- ### 1. Secure Password Requirements
25
-
26
- ```typescript
27
- import { passwordSchema, securePasswordSchema, calculatePasswordStrength } from '@jmruthers/pace-core/utils/validation';
28
- import { isStrongPassword } from '@jmruthers/pace-core/utils/validation';
29
-
30
- // Using Zod schema (recommended)
31
- function validateUserPassword(password: string) {
32
- const result = securePasswordSchema.safeParse(password);
33
- if (!result.success) {
34
- return { valid: false, errors: result.error.errors };
35
- }
36
- return { valid: true };
37
- }
38
-
39
- // Using simple validation function
40
- function checkPasswordStrength(password: string) {
41
- const strength = calculatePasswordStrength(password);
42
- return {
43
- isValid: strength.level !== 'very-weak' && strength.level !== 'weak',
44
- strength: strength.level,
45
- score: strength.score,
46
- feedback: strength.feedback
47
- };
48
- }
49
-
50
- // Basic validation
51
- const isValid = isStrongPassword(password); // Returns boolean
52
- ```
53
-
54
- ### 2. Password Strength Indicator
55
-
56
- ```typescript
57
- import { calculatePasswordStrength } from '@jmruthers/pace-core/utils/validation';
58
-
59
- function PasswordInput() {
60
- const [password, setPassword] = useState('');
61
- const strength = calculatePasswordStrength(password);
62
-
63
- return (
64
- <div>
65
- <input
66
- type="password"
67
- value={password}
68
- onChange={(e) => setPassword(e.target.value)}
69
- />
70
- <div className={`strength-${strength.level}`}>
71
- Strength: {strength.level} ({strength.score}/100)
72
- </div>
73
- {strength.feedback.length > 0 && (
74
- <ul>
75
- {strength.feedback.map((msg, i) => (
76
- <li key={i}>{msg}</li>
77
- ))}
78
- </ul>
79
- )}
80
- </div>
81
- );
82
- }
83
- ```
84
-
85
- ### 3. Session Management
86
-
87
- ```typescript
88
- import { useUnifiedAuth } from '@jmruthers/pace-core';
89
-
90
- function SessionManager() {
91
- const { session, signOut, refreshSession } = useUnifiedAuth();
92
-
93
- // Auto-refresh session before expiry
94
- useEffect(() => {
95
- if (session && session.expires_at) {
96
- const timeUntilExpiry = session.expires_at * 1000 - Date.now();
97
- const refreshTime = Math.max(timeUntilExpiry - 5 * 60 * 1000, 0); // 5 minutes before expiry
98
-
99
- const timer = setTimeout(() => {
100
- refreshSession();
101
- }, refreshTime);
102
-
103
- return () => clearTimeout(timer);
104
- }
105
- }, [session, refreshSession]);
106
-
107
- return (
108
- <div>
109
- <p>Session expires: {new Date(session?.expires_at * 1000).toLocaleString()}</p>
110
- <button onClick={signOut}>Sign Out</button>
111
- </div>
112
- );
113
- }
114
- ```
115
-
116
- ## Authorization Security
117
-
118
- ### 1. Server-Side Permission Validation
119
-
120
- Always validate permissions on the server side:
121
-
122
- ```typescript
123
- // Server-side middleware
124
- function withPermission(permission: string) {
125
- return async (req: Request, res: Response, next: NextFunction) => {
126
- const user = req.user;
127
-
128
- if (!user) {
129
- return res.status(401).json({ error: 'Unauthorized' });
130
- }
131
-
132
- const hasPermission = await checkUserPermission(user.id, permission);
133
-
134
- if (!hasPermission) {
135
- return res.status(403).json({ error: 'Insufficient permissions' });
136
- }
137
-
138
- next();
139
- };
140
- }
141
-
142
- // API route protection
143
- app.get('/api/users', withPermission('read:users'), (req, res) => {
144
- // Handle request
145
- });
146
- ```
147
-
148
- ### 2. Organisation Access Validation
149
-
150
- ```typescript
151
- // Validate organisation access
152
- function validateOrganisationAccess(userId: string, organisationId: string): Promise<boolean> {
153
- return supabase
154
- .from('organisation_members')
155
- .select('*')
156
- .eq('user_id', userId)
157
- .eq('organisation_id', organisationId)
158
- .eq('status', 'active')
159
- .single()
160
- .then(result => !!result.data);
161
- }
162
-
163
- // Use in API routes
164
- app.get('/api/organisations/:id/data', async (req, res) => {
165
- const { id } = req.params;
166
- const userId = req.user.id;
167
-
168
- const hasAccess = await validateOrganisationAccess(userId, id);
169
-
170
- if (!hasAccess) {
171
- return res.status(403).json({ error: 'Access denied' });
172
- }
173
-
174
- // Proceed with data access
175
- });
176
- ```
177
-
178
- ### 3. Row Level Security (RLS)
179
-
180
- Enable RLS on all tables and create appropriate policies:
181
-
182
- ```sql
183
- -- Enable RLS on events table
184
- ALTER TABLE events ENABLE ROW LEVEL SECURITY;
185
-
186
- -- Policy for reading events
187
- CREATE POLICY "Users can view events in their organisation" ON events
188
- FOR SELECT USING (
189
- organisation_id IN (
190
- SELECT organisation_id
191
- FROM organisation_members
192
- WHERE user_id = auth.uid() AND status = 'active'
193
- )
194
- );
195
-
196
- -- Policy for creating events
197
- CREATE POLICY "Users can create events in their organisation" ON events
198
- FOR INSERT WITH CHECK (
199
- organisation_id IN (
200
- SELECT organisation_id
201
- FROM organisation_members
202
- WHERE user_id = auth.uid() AND status = 'active'
203
- )
204
- );
205
-
206
- -- Policy for updating events
207
- CREATE POLICY "Users can update events they created" ON events
208
- FOR UPDATE USING (
209
- created_by = auth.uid() OR
210
- organisation_id IN (
211
- SELECT organisation_id
212
- FROM organisation_members
213
- WHERE user_id = auth.uid() AND role IN ('admin', 'owner')
214
- )
215
- );
216
- ```
217
-
218
- ## Input Validation and Sanitization
219
-
220
- ### 1. Form Validation
221
-
222
- ```typescript
223
- import { useZodForm } from '@jmruthers/pace-core';
224
- import { z } from 'zod';
225
-
226
- const userSchema = z.object({
227
- name: z.string()
228
- .min(1, 'Name is required')
229
- .max(100, 'Name must be less than 100 characters')
230
- .regex(/^[a-zA-Z\s]+$/, 'Name can only contain letters and spaces'),
231
-
232
- email: z.string()
233
- .email('Invalid email address')
234
- .max(255, 'Email must be less than 255 characters'),
235
-
236
- phone: z.string()
237
- .regex(/^\+?[1-9]\d{1,14}$/, 'Invalid phone number')
238
- .optional(),
239
-
240
- age: z.number()
241
- .min(13, 'Must be at least 13 years old')
242
- .max(120, 'Invalid age'),
243
- });
244
-
245
- function UserForm() {
246
- const { register, handleSubmit, errors } = useZodForm(userSchema);
247
-
248
- const onSubmit = async (data: z.infer<typeof userSchema>) => {
249
- // Data is validated and sanitized
250
- await createUser(data);
251
- };
252
-
253
- return (
254
- <form onSubmit={handleSubmit(onSubmit)}>
255
- <input {...register('name')} />
256
- {errors.name && <span>{errors.name.message}</span>}
257
-
258
- <input type="email" {...register('email')} />
259
- {errors.email && <span>{errors.email.message}</span>}
260
-
261
- <input type="tel" {...register('phone')} />
262
- {errors.phone && <span>{errors.phone.message}</span>}
263
-
264
- <input type="number" {...register('age')} />
265
- {errors.age && <span>{errors.age.message}</span>}
266
-
267
- <button type="submit">Submit</button>
268
- </form>
269
- );
270
- }
271
- ```
272
-
273
- ### 2. HTML Sanitization
274
-
275
- ```typescript
276
- import { sanitizeHtml } from '@jmruthers/pace-core';
277
-
278
- function RichTextEditor() {
279
- const [content, setContent] = useState('');
280
-
281
- const handleSave = () => {
282
- // Sanitize HTML before saving
283
- const sanitizedContent = sanitizeHtml(content, {
284
- allowedTags: ['p', 'br', 'strong', 'em', 'ul', 'ol', 'li'],
285
- allowedAttributes: {},
286
- });
287
-
288
- saveContent(sanitizedContent);
289
- };
290
-
291
- return (
292
- <div>
293
- <textarea
294
- value={content}
295
- onChange={(e) => setContent(e.target.value)}
296
- placeholder="Enter content..."
297
- />
298
- <button onClick={handleSave}>Save</button>
299
- </div>
300
- );
301
- }
302
- ```
303
-
304
- ### 3. File Upload Security
305
-
306
- ```typescript
307
- import { validateFileUpload } from '@jmruthers/pace-core';
308
-
309
- const fileUploadConfig = {
310
- maxSize: 5 * 1024 * 1024, // 5MB
311
- allowedTypes: ['image/jpeg', 'image/png', 'image/gif'],
312
- allowedExtensions: ['.jpg', '.jpeg', '.png', '.gif'],
313
- };
314
-
315
- function FileUpload() {
316
- const handleFileUpload = async (file: File) => {
317
- try {
318
- const validation = await validateFileUpload(file, fileUploadConfig);
319
-
320
- if (!validation.isValid) {
321
- throw new Error(validation.error);
322
- }
323
-
324
- // Proceed with upload
325
- await uploadFile(file);
326
- } catch (error) {
327
- console.error('File upload failed:', error);
328
- }
329
- };
330
-
331
- return (
332
- <input
333
- type="file"
334
- accept="image/*"
335
- onChange={(e) => {
336
- const file = e.target.files?.[0];
337
- if (file) handleFileUpload(file);
338
- }}
339
- />
340
- );
341
- }
342
- ```
343
-
344
- ## CSRF Protection
345
-
346
- ### 1. CSRF Token Generation
347
-
348
- ```typescript
349
- import { generateCSRFToken, validateCSRFToken } from '@jmruthers/pace-core';
350
-
351
- // Generate CSRF token
352
- const csrfToken = generateCSRFToken();
353
-
354
- // Include in forms
355
- function SecureForm() {
356
- return (
357
- <form>
358
- <input type="hidden" name="_csrf" value={csrfToken} />
359
- {/* Form fields */}
360
- </form>
361
- );
362
- }
363
- ```
364
-
365
- ### 2. CSRF Token Validation
366
-
367
- ```typescript
368
- // Server-side validation
369
- function validateCSRFRequest(req: Request, res: Response, next: NextFunction) {
370
- const token = req.headers['x-csrf-token'] || req.body._csrf;
371
-
372
- if (!validateCSRFToken(token)) {
373
- return res.status(403).json({ error: 'Invalid CSRF token' });
374
- }
375
-
376
- next();
377
- }
378
-
379
- // Apply to sensitive routes
380
- app.post('/api/users', validateCSRFRequest, (req, res) => {
381
- // Handle request
382
- });
383
- ```
384
-
385
- ## XSS Prevention
386
-
387
- ### 1. Content Security Policy (CSP)
388
-
389
- ```typescript
390
- // Set CSP headers
391
- const cspHeaders = {
392
- 'Content-Security-Policy': [
393
- "default-src 'self'",
394
- "script-src 'self' 'unsafe-inline'",
395
- "style-src 'self' 'unsafe-inline'",
396
- "img-src 'self' data: https:",
397
- "font-src 'self'",
398
- "connect-src 'self'",
399
- "frame-ancestors 'none'",
400
- ].join('; '),
401
- };
402
-
403
- // Apply to all responses
404
- app.use((req, res, next) => {
405
- Object.entries(cspHeaders).forEach(([key, value]) => {
406
- res.setHeader(key, value);
407
- });
408
- next();
409
- });
410
- ```
411
-
412
- ### 2. Safe HTML Rendering
413
-
414
- ```typescript
415
- import { sanitizeHtml } from '@jmruthers/pace-core';
416
-
417
- function SafeContent({ content }: { content: string }) {
418
- const sanitizedContent = sanitizeHtml(content, {
419
- allowedTags: ['p', 'br', 'strong', 'em'],
420
- allowedAttributes: {},
421
- });
422
-
423
- return (
424
- <div
425
- dangerouslySetInnerHTML={{ __html: sanitizedContent }}
426
- className="safe-content"
427
- />
428
- );
429
- }
430
- ```
431
-
432
- ## API Security
433
-
434
- ### 1. Rate Limiting
435
-
436
- ```typescript
437
- import rateLimit from 'express-rate-limit';
438
-
439
- const authLimiter = rateLimit({
440
- windowMs: 15 * 60 * 1000, // 15 minutes
441
- max: 5, // limit each IP to 5 requests per windowMs
442
- message: 'Too many authentication attempts, please try again later',
443
- });
444
-
445
- const apiLimiter = rateLimit({
446
- windowMs: 15 * 60 * 1000, // 15 minutes
447
- max: 100, // limit each IP to 100 requests per windowMs
448
- });
449
-
450
- // Apply to routes
451
- app.use('/api/auth', authLimiter);
452
- app.use('/api', apiLimiter);
453
- ```
454
-
455
- ### 2. Request Validation
456
-
457
- ```typescript
458
- import { validateRequest } from '@jmruthers/pace-core';
459
-
460
- const userValidationSchema = z.object({
461
- name: z.string().min(1).max(100),
462
- email: z.string().email(),
463
- age: z.number().min(13).max(120),
464
- });
465
-
466
- function createUser(req: Request, res: Response) {
467
- const validation = validateRequest(req.body, userValidationSchema);
468
-
469
- if (!validation.isValid) {
470
- return res.status(400).json({
471
- error: 'Invalid request data',
472
- details: validation.errors
473
- });
474
- }
475
-
476
- // Proceed with user creation
477
- }
478
- ```
479
-
480
- ### 3. Secure Headers
481
-
482
- ```typescript
483
- import helmet from 'helmet';
484
-
485
- // Apply security headers
486
- app.use(helmet({
487
- contentSecurityPolicy: {
488
- directives: {
489
- defaultSrc: ["'self'"],
490
- scriptSrc: ["'self'", "'unsafe-inline'"],
491
- styleSrc: ["'self'", "'unsafe-inline'"],
492
- imgSrc: ["'self'", "data:", "https:"],
493
- },
494
- },
495
- hsts: {
496
- maxAge: 31536000,
497
- includeSubDomains: true,
498
- preload: true,
499
- },
500
- }));
501
- ```
502
-
503
- ## Data Security
504
-
505
- ### 1. Sensitive Data Encryption
506
-
507
- ```typescript
508
- import { encryptData, decryptData } from '@jmruthers/pace-core';
509
-
510
- // Encrypt sensitive data before storing
511
- const sensitiveData = {
512
- creditCard: '1234-5678-9012-3456',
513
- ssn: '123-45-6789',
514
- };
515
-
516
- const encryptedData = encryptData(JSON.stringify(sensitiveData));
517
-
518
- // Store encrypted data
519
- await supabase
520
- .from('user_sensitive_data')
521
- .insert({
522
- user_id: userId,
523
- encrypted_data: encryptedData,
524
- });
525
-
526
- // Decrypt when needed
527
- const decryptedData = JSON.parse(decryptData(encryptedData));
528
- ```
529
-
530
- ### 2. Secure Data Transmission
531
-
532
- ```typescript
533
- // Always use HTTPS in production
534
- if (process.env.NODE_ENV === 'production') {
535
- app.use((req, res, next) => {
536
- if (!req.secure) {
537
- return res.redirect(`https://${req.headers.host}${req.url}`);
538
- }
539
- next();
540
- });
541
- }
542
- ```
543
-
544
- ### 3. Audit Logging
545
-
546
- ```typescript
547
- import { createAuditLog } from '@jmruthers/pace-core';
548
-
549
- // Log security events
550
- async function logSecurityEvent(event: string, userId: string, details: any) {
551
- await createAuditLog({
552
- event,
553
- user_id: userId,
554
- details,
555
- timestamp: new Date().toISOString(),
556
- ip_address: req.ip,
557
- user_agent: req.headers['user-agent'],
558
- });
559
- }
560
-
561
- // Use in sensitive operations
562
- app.post('/api/users/:id/delete', async (req, res) => {
563
- const { id } = req.params;
564
- const userId = req.user.id;
565
-
566
- await deleteUser(id);
567
-
568
- await logSecurityEvent('user_deleted', userId, {
569
- deleted_user_id: id,
570
- reason: req.body.reason,
571
- });
572
-
573
- res.json({ success: true });
574
- });
575
- ```
576
-
577
- ## Environment Security
578
-
579
- ### 1. Environment Variables
580
-
581
- ```typescript
582
- // Validate required environment variables
583
- const requiredEnvVars = [
584
- 'SUPABASE_URL',
585
- 'SUPABASE_ANON_KEY',
586
- 'SUPABASE_SERVICE_ROLE_KEY',
587
- 'JWT_SECRET',
588
- 'ENCRYPTION_KEY',
589
- ];
590
-
591
- requiredEnvVars.forEach(varName => {
592
- if (!process.env[varName]) {
593
- throw new Error(`Missing required environment variable: ${varName}`);
594
- }
595
- });
596
- ```
597
-
598
- ### 2. Secure Configuration
599
-
600
- ```typescript
601
- // Production security settings
602
- const securityConfig = {
603
- production: {
604
- cors: {
605
- origin: process.env.ALLOWED_ORIGINS?.split(',') || [],
606
- credentials: true,
607
- },
608
- session: {
609
- secure: true,
610
- httpOnly: true,
611
- sameSite: 'strict',
612
- },
613
- rateLimit: {
614
- windowMs: 15 * 60 * 1000,
615
- max: 100,
616
- },
617
- },
618
- development: {
619
- cors: {
620
- origin: true,
621
- credentials: true,
622
- },
623
- session: {
624
- secure: false,
625
- httpOnly: true,
626
- sameSite: 'lax',
627
- },
628
- rateLimit: {
629
- windowMs: 15 * 60 * 1000,
630
- max: 1000,
631
- },
632
- },
633
- };
634
- ```
635
-
636
- ## Security Testing
637
-
638
- ### 1. Security Headers Testing
639
-
640
- ```typescript
641
- import { testSecurityHeaders } from '@jmruthers/pace-core';
642
-
643
- test('security headers are set correctly', async () => {
644
- const response = await request(app)
645
- .get('/api/health')
646
- .expect(200);
647
-
648
- expect(response.headers).toHaveProperty('x-content-type-options');
649
- expect(response.headers['x-content-type-options']).toBe('nosniff');
650
-
651
- expect(response.headers).toHaveProperty('x-frame-options');
652
- expect(response.headers['x-frame-options']).toBe('DENY');
653
-
654
- expect(response.headers).toHaveProperty('x-xss-protection');
655
- expect(response.headers['x-xss-protection']).toBe('1; mode=block');
656
- });
657
- ```
658
-
659
- ### 2. Authentication Testing
660
-
661
- ```typescript
662
- test('unauthenticated requests are rejected', async () => {
663
- await request(app)
664
- .get('/api/users')
665
- .expect(401);
666
- });
667
-
668
- test('unauthorized requests are rejected', async () => {
669
- const user = await createTestUser({ role: 'user' });
670
- const token = await generateAuthToken(user);
671
-
672
- await request(app)
673
- .get('/api/admin/users')
674
- .set('Authorization', `Bearer ${token}`)
675
- .expect(403);
676
- });
677
- ```
678
-
679
- ### 3. Input Validation Testing
680
-
681
- ```typescript
682
- test('malicious input is sanitized', async () => {
683
- const maliciousInput = '<script>alert("xss")</script>';
684
-
685
- const response = await request(app)
686
- .post('/api/users')
687
- .send({
688
- name: maliciousInput,
689
- email: 'test@example.com',
690
- })
691
- .expect(400);
692
-
693
- expect(response.body.error).toContain('Invalid input');
694
- });
695
- ```
696
-
697
- ## Security Monitoring
698
-
699
- ### 1. Security Event Monitoring
700
-
701
- ```typescript
702
- import { monitorSecurityEvents } from '@jmruthers/pace-core';
703
-
704
- // Monitor security events
705
- monitorSecurityEvents({
706
- onFailedLogin: (event) => {
707
- console.warn('Failed login attempt:', event);
708
- // Send alert to security team
709
- },
710
- onSuspiciousActivity: (event) => {
711
- console.error('Suspicious activity detected:', event);
712
- // Trigger security response
713
- },
714
- onPermissionViolation: (event) => {
715
- console.error('Permission violation:', event);
716
- // Log for investigation
717
- },
718
- });
719
- ```
720
-
721
- ### 2. Security Metrics
722
-
723
- ```typescript
724
- import { trackSecurityMetrics } from '@jmruthers/pace-core';
725
-
726
- // Track security metrics
727
- trackSecurityMetrics({
728
- failedLogins: 0,
729
- successfulLogins: 0,
730
- permissionDenials: 0,
731
- suspiciousActivities: 0,
732
- });
733
-
734
- // Export metrics for monitoring
735
- app.get('/api/security/metrics', (req, res) => {
736
- res.json(getSecurityMetrics());
737
- });
738
- ```
739
-
740
- ## Incident Response
741
-
742
- ### 1. Security Incident Handling
743
-
744
- ```typescript
745
- import { handleSecurityIncident } from '@jmruthers/pace-core';
746
-
747
- // Handle security incidents
748
- async function handleSecurityIncident(incident: SecurityIncident) {
749
- // Log the incident
750
- await logSecurityEvent('security_incident', incident.userId, incident);
751
-
752
- // Take immediate action
753
- if (incident.type === 'brute_force') {
754
- await lockUserAccount(incident.userId);
755
- await notifySecurityTeam(incident);
756
- }
757
-
758
- if (incident.type === 'data_breach') {
759
- await revokeAllSessions(incident.userId);
760
- await forcePasswordReset(incident.userId);
761
- await notifyUser(incident.userId, 'security_alert');
762
- }
763
- }
764
- ```
765
-
766
- ### 2. Security Alerts
767
-
768
- ```typescript
769
- import { createSecurityAlert } from '@jmruthers/pace-core';
770
-
771
- // Create security alerts
772
- async function createSecurityAlert(alert: SecurityAlert) {
773
- await createAuditLog({
774
- event: 'security_alert',
775
- user_id: alert.userId,
776
- details: alert,
777
- severity: alert.severity,
778
- timestamp: new Date().toISOString(),
779
- });
780
-
781
- // Send notification based on severity
782
- if (alert.severity === 'high') {
783
- await sendImmediateAlert(alert);
784
- }
785
- }
786
- ```
787
-
788
- ## Compliance and Standards
789
-
790
- ### 1. GDPR Compliance
791
-
792
- ```typescript
793
- import { gdprCompliance } from '@jmruthers/pace-core';
794
-
795
- // GDPR compliance utilities
796
- const gdprUtils = {
797
- // Right to be forgotten
798
- deleteUserData: async (userId: string) => {
799
- await supabase.from('users').delete().eq('id', userId);
800
- await supabase.from('user_data').delete().eq('user_id', userId);
801
- await logSecurityEvent('gdpr_deletion', userId, { reason: 'right_to_be_forgotten' });
802
- },
803
-
804
- // Data portability
805
- exportUserData: async (userId: string) => {
806
- const userData = await supabase
807
- .from('users')
808
- .select('*')
809
- .eq('id', userId)
810
- .single();
811
-
812
- return JSON.stringify(userData, null, 2);
813
- },
814
-
815
- // Consent management
816
- updateConsent: async (userId: string, consent: ConsentSettings) => {
817
- await supabase
818
- .from('user_consent')
819
- .upsert({
820
- user_id: userId,
821
- marketing_emails: consent.marketingEmails,
822
- analytics_tracking: consent.analyticsTracking,
823
- updated_at: new Date().toISOString(),
824
- });
825
- },
826
- };
827
- ```
828
-
829
- ### 2. SOC 2 Compliance
830
-
831
- ```typescript
832
- import { soc2Compliance } from '@jmruthers/pace-core';
833
-
834
- // SOC 2 compliance monitoring
835
- const soc2Utils = {
836
- // Access control monitoring
837
- monitorAccess: async (userId: string, resource: string, action: string) => {
838
- await createAuditLog({
839
- event: 'access_attempt',
840
- user_id: userId,
841
- details: { resource, action, timestamp: new Date().toISOString() },
842
- });
843
- },
844
-
845
- // Data integrity checks
846
- verifyDataIntegrity: async () => {
847
- // Implement data integrity verification
848
- const checksum = await calculateDataChecksum();
849
- return checksum;
850
- },
851
-
852
- // Backup verification
853
- verifyBackups: async () => {
854
- // Implement backup verification
855
- const backupStatus = await checkBackupStatus();
856
- return backupStatus;
857
- },
858
- };
859
- ```
860
-
861
- ## Security Checklist
862
-
863
- ### Pre-Deployment Checklist
864
-
865
- - [ ] All environment variables are properly set
866
- - [ ] HTTPS is enabled in production
867
- - [ ] Security headers are configured
868
- - [ ] Rate limiting is implemented
869
- - [ ] Input validation is in place
870
- - [ ] CSRF protection is enabled
871
- - [ ] XSS protection is implemented
872
- - [ ] SQL injection protection is active
873
- - [ ] File upload validation is configured
874
- - [ ] Audit logging is enabled
875
- - [ ] Error messages don't leak sensitive information
876
- - [ ] Session management is secure
877
- - [ ] Password requirements are enforced
878
- - [ ] Multi-factor authentication is available
879
- - [ ] Row-level security is enabled
880
- - [ ] API endpoints are properly protected
881
-
882
- ### Ongoing Security Maintenance
883
-
884
- - [ ] Regular security updates
885
- - [ ] Dependency vulnerability scanning
886
- - [ ] Security audit logging review
887
- - [ ] Penetration testing
888
- - [ ] Security incident response plan
889
- - [ ] User access review
890
- - [ ] Data backup verification
891
- - [ ] Compliance monitoring
892
-
893
- For more information about implementing security in your application, see the [Authentication Guide](../core-concepts/authentication.md) and [RBAC System Guide](../core-concepts/rbac-system.md).
894
-
895
- ## ♿ Accessibility
896
-
897
- Security practices should maintain accessibility:
898
-
899
- - **Error messages are accessible** - Security errors should be clearly communicated
900
- - **Authentication flows are keyboard accessible** - All security forms should support keyboard navigation
901
- - **Screen reader support** - Security messages should be properly announced
902
- - **Focus management** - Ensure focus is properly managed during security operations
903
- - **Timeouts are announced** - Session timeouts should be accessible to screen readers
904
-
905
- ### Accessibility Best Practices
906
-
907
- 1. **Test authentication with screen readers** - Verify login flows work with assistive technologies
908
- 2. **Ensure keyboard access** - All security forms should be keyboard accessible
909
- 3. **Provide clear error messages** - Security errors should be descriptive without exposing vulnerabilities
910
- 4. **Announce security state changes** - Use ARIA live regions for security status updates
911
- 5. **Test with assistive technologies** - Verify all security features work with screen readers
912
-
913
- ## ⚠️ Edge Cases
914
-
915
- ### Security vs Usability Conflicts
916
-
917
- When security measures impact usability:
918
- - Find balance between security and user experience
919
- - Provide clear guidance for security requirements
920
- - Implement security transparently
921
- - Test with real users to ensure usability
922
- - Document security decisions
923
-
924
- ### Rate Limiting Edge Cases
925
-
926
- When rate limiting causes issues:
927
- - Provide clear error messages for rate limit violations
928
- - Implement progressive backoff for retries
929
- - Consider user experience when setting limits
930
- - Monitor rate limit effectiveness
931
- - Adjust limits based on legitimate use patterns
932
-
933
- ### Session Management Edge Cases
934
-
935
- When session management fails:
936
- - Handle session expiration gracefully
937
- - Provide clear messages for session issues
938
- - Ensure proper cleanup on session end
939
- - Test with multiple concurrent sessions
940
- - Verify session security across devices