@jmruthers/pace-core 0.6.6 → 0.6.8

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 (292) hide show
  1. package/{scripts/audit/audit-dependencies.cjs → audit-tool/00-dependencies.cjs} +227 -22
  2. package/audit-tool/audits/01-pace-core-compliance.cjs +556 -0
  3. package/audit-tool/audits/02-project-structure.cjs +240 -0
  4. package/audit-tool/audits/03-architecture.cjs +224 -0
  5. package/audit-tool/audits/04-code-quality.cjs +149 -0
  6. package/audit-tool/audits/05-styling.cjs +224 -0
  7. package/audit-tool/audits/06-security-rbac.cjs +554 -0
  8. package/audit-tool/audits/07-api-tech-stack.cjs +355 -0
  9. package/audit-tool/audits/08-testing-documentation.cjs +202 -0
  10. package/audit-tool/audits/09-operations.cjs +208 -0
  11. package/audit-tool/index.cjs +295 -0
  12. package/audit-tool/utils/code-utils.cjs +218 -0
  13. package/audit-tool/utils/file-utils.cjs +230 -0
  14. package/audit-tool/utils/report-utils.cjs +380 -0
  15. package/cursor-rules/00-standards-overview.mdc +156 -0
  16. package/cursor-rules/{00-pace-core-compliance.mdc → 01-pace-core-compliance.mdc} +187 -34
  17. package/cursor-rules/02-project-structure.mdc +37 -5
  18. package/cursor-rules/{03-solid-principles.mdc → 03-architecture.mdc} +125 -11
  19. package/cursor-rules/04-code-quality.mdc +419 -0
  20. package/cursor-rules/{08-markup-quality.mdc → 05-styling.mdc} +55 -10
  21. package/cursor-rules/{09-rbac-compliance.mdc → 06-security-rbac.mdc} +62 -6
  22. package/cursor-rules/07-api-tech-stack.mdc +377 -0
  23. package/cursor-rules/08-testing-documentation.mdc +324 -0
  24. package/cursor-rules/09-operations.mdc +365 -0
  25. package/dist/DataTable-6RMSCQJ6.js +15 -0
  26. package/dist/{DataTable-2N_tqbfq.d.ts → DataTable-DRUIgtUH.d.ts} +1 -1
  27. package/dist/{PublicPageProvider-BBH6Vqg7.d.ts → PublicPageProvider-CIGSujI2.d.ts} +40 -24
  28. package/dist/{UnifiedAuthProvider-ZT6TIGM7.js → UnifiedAuthProvider-7SNDOWYD.js} +2 -2
  29. package/dist/{api-Y4MQWOFW.js → api-7P7DI652.js} +1 -1
  30. package/dist/{chunk-MAGBIDNS.js → chunk-4DDCYDQ3.js} +8 -7
  31. package/dist/{chunk-BVP2BCJF.js → chunk-5W2A3DRC.js} +10 -9
  32. package/dist/{chunk-SD6WQY43.js → chunk-7ILTDCL2.js} +9 -1
  33. package/dist/{chunk-3QC3KRHK.js → chunk-A3W6LW53.js} +16 -1
  34. package/dist/{chunk-3O3WHILE.js → chunk-EF2UGZWY.js} +239 -63
  35. package/dist/{chunk-LAZMKTTF.js → chunk-EURB7QFZ.js} +341 -337
  36. package/dist/{chunk-2HGJFNAH.js → chunk-FEJLJNWA.js} +1 -15
  37. package/dist/{chunk-7TYHROIV.js → chunk-GS5672WG.js} +55 -13
  38. package/dist/{chunk-UIYSCEV7.js → chunk-IUBRCBSY.js} +1 -1
  39. package/dist/{chunk-ZFYPMX46.js → chunk-LX6U42O3.js} +1 -1
  40. package/dist/{chunk-FENMYN2U.js → chunk-MPBLMWVR.js} +3 -3
  41. package/dist/{chunk-ZS5VO5JB.js → chunk-NKHKXPI4.js} +408 -453
  42. package/dist/{chunk-A55DK444.js → chunk-OJ4SKRSV.js} +1 -7
  43. package/dist/{chunk-4T7OBVTU.js → chunk-S6ZQKDY6.js} +1 -1
  44. package/dist/{chunk-FTCRZOG2.js → chunk-T5CVK4R3.js} +5 -5
  45. package/dist/{chunk-OHIK3MIO.js → chunk-Z2FNRKF3.js} +13 -13
  46. package/dist/components.d.ts +5 -4
  47. package/dist/components.js +29 -34
  48. package/dist/eslint-rules/index.cjs +22 -9
  49. package/{src/eslint-rules/rules/compliance.cjs → dist/eslint-rules/rules/01-pace-core-compliance.cjs} +184 -23
  50. package/dist/eslint-rules/rules/04-code-quality.cjs +346 -0
  51. package/dist/eslint-rules/rules/05-styling.cjs +61 -0
  52. package/dist/eslint-rules/rules/{rbac.cjs → 06-security-rbac.cjs} +34 -13
  53. package/dist/eslint-rules/rules/07-api-tech-stack.cjs +385 -0
  54. package/dist/eslint-rules/rules/08-testing.cjs +94 -0
  55. package/dist/{functions-DHebl8-F.d.ts → functions-lBy5L2ry.d.ts} +1 -1
  56. package/dist/hooks.d.ts +5 -5
  57. package/dist/hooks.js +8 -8
  58. package/dist/index.d.ts +7 -7
  59. package/dist/index.js +21 -20
  60. package/dist/providers.js +2 -2
  61. package/dist/rbac/index.d.ts +1 -1
  62. package/dist/rbac/index.js +8 -8
  63. package/dist/theming/runtime.d.ts +61 -1
  64. package/dist/theming/runtime.js +1 -1
  65. package/dist/{types-B-K_5VnO.d.ts → types-DXstZpNI.d.ts} +0 -17
  66. package/dist/types.d.ts +2 -2
  67. package/dist/{usePublicRouteParams-COZ28Mvq.d.ts → usePublicRouteParams-MamNgwqe.d.ts} +19 -19
  68. package/dist/utils.d.ts +2 -2
  69. package/dist/utils.js +8 -8
  70. package/docs/README.md +1 -1
  71. package/docs/api/modules.md +106 -41
  72. package/docs/api-reference/components.md +18 -20
  73. package/docs/api-reference/hooks.md +80 -80
  74. package/docs/api-reference/types.md +1 -1
  75. package/docs/api-reference/utilities.md +1 -1
  76. package/docs/architecture/README.md +1 -1
  77. package/docs/core-concepts/events.md +3 -3
  78. package/docs/core-concepts/organisations.md +6 -6
  79. package/docs/core-concepts/permissions.md +6 -6
  80. package/docs/documentation-index.md +12 -18
  81. package/docs/getting-started/dependencies.md +23 -0
  82. package/docs/getting-started/documentation-index.md +1 -1
  83. package/docs/getting-started/examples/README.md +4 -4
  84. package/docs/getting-started/examples/full-featured-app.md +1 -1
  85. package/docs/getting-started/faq.md +2 -2
  86. package/docs/getting-started/quick-reference.md +4 -4
  87. package/docs/implementation-guides/app-layout.md +1 -1
  88. package/docs/implementation-guides/authentication.md +15 -15
  89. package/docs/implementation-guides/component-styling.md +1 -1
  90. package/docs/implementation-guides/data-tables.md +127 -34
  91. package/docs/implementation-guides/datatable-rbac-usage.md +1 -1
  92. package/docs/implementation-guides/dynamic-colors.md +3 -3
  93. package/docs/implementation-guides/file-upload-storage.md +2 -2
  94. package/docs/implementation-guides/hierarchical-datatable.md +40 -60
  95. package/docs/implementation-guides/inactivity-tracking.md +3 -3
  96. package/docs/implementation-guides/large-datasets.md +3 -2
  97. package/docs/implementation-guides/organisation-security.md +2 -2
  98. package/docs/implementation-guides/performance.md +2 -2
  99. package/docs/implementation-guides/permission-enforcement.md +1 -1
  100. package/docs/migration/V0.3.44_organisation-context-timing-fix.md +1 -1
  101. package/docs/migration/V0.4.0_rbac-migration.md +6 -6
  102. package/docs/rbac/README.md +5 -5
  103. package/docs/rbac/advanced-patterns.md +6 -6
  104. package/docs/rbac/api-reference.md +20 -20
  105. package/docs/rbac/event-based-apps.md +3 -3
  106. package/docs/rbac/examples.md +41 -41
  107. package/docs/rbac/getting-started.md +37 -37
  108. package/docs/rbac/performance.md +1 -1
  109. package/docs/rbac/quick-start.md +52 -52
  110. package/docs/rbac/secure-client-protection.md +1 -1
  111. package/docs/rbac/troubleshooting.md +1 -1
  112. package/docs/security/README.md +5 -5
  113. package/docs/standards/0-standards-overview.md +220 -0
  114. package/docs/standards/{00-pace-core-compliance.md → 1-pace-core-compliance-standards.md} +241 -185
  115. package/docs/standards/{02-project-structure.md → 2-project-structure-standards.md} +11 -47
  116. package/docs/standards/3-architecture-standards.md +606 -0
  117. package/docs/standards/4-code-quality-standards.md +728 -0
  118. package/docs/standards/{08-markup-quality.md → 5-styling-standards.md} +12 -9
  119. package/docs/standards/{09-rbac-compliance.md → 6-security-rbac-standards.md} +126 -18
  120. package/docs/standards/7-api-tech-stack-standards.md +662 -0
  121. package/docs/standards/8-testing-documentation-standards.md +401 -0
  122. package/docs/standards/9-operations-standards.md +1102 -0
  123. package/docs/standards/README.md +203 -104
  124. package/docs/troubleshooting/README.md +4 -4
  125. package/docs/troubleshooting/common-issues.md +2 -2
  126. package/docs/troubleshooting/debugging.md +9 -9
  127. package/docs/troubleshooting/migration.md +4 -4
  128. package/eslint-config-pace-core.cjs +50 -20
  129. package/package.json +50 -19
  130. package/scripts/eslint-audit.cjs +123 -0
  131. package/scripts/install-cursor-rules.cjs +11 -243
  132. package/scripts/install-eslint-config.cjs +349 -0
  133. package/scripts/validate-dependencies.cjs +248 -0
  134. package/src/__tests__/helpers/__tests__/component-test-utils.test.tsx +2 -2
  135. package/src/__tests__/helpers/__tests__/test-providers.test.tsx +2 -2
  136. package/src/__tests__/helpers/__tests__/test-utils.test.tsx +30 -18
  137. package/src/__tests__/integration/UserProfile.test.tsx +14 -14
  138. package/src/__tests__/rbac/PagePermissionGuard.test.tsx +6 -6
  139. package/src/__tests__/templates/accessibility.test.template.tsx +10 -9
  140. package/src/__tests__/templates/component.test.template.tsx +18 -15
  141. package/src/components/AddressField/AddressField.tsx +26 -1
  142. package/src/components/Alert/Alert.test.tsx +86 -22
  143. package/src/components/Alert/Alert.tsx +19 -11
  144. package/src/components/Badge/Badge.tsx +1 -1
  145. package/src/components/Calendar/Calendar.tsx +201 -47
  146. package/src/components/Checkbox/Checkbox.test.tsx +2 -1
  147. package/src/components/ContextSelector/ContextSelector.tsx +108 -126
  148. package/src/components/DataTable/AUDIT_REPORT.md +293 -0
  149. package/src/components/DataTable/DataTable.tsx +1 -19
  150. package/src/components/DataTable/__tests__/DataTableCore.test.tsx +6 -2
  151. package/src/components/DataTable/__tests__/a11y.basic.test.tsx +21 -6
  152. package/src/components/DataTable/__tests__/pagination.modes.test.tsx +3 -2
  153. package/src/components/DataTable/__tests__/test-utils/sharedTestUtils.tsx +9 -9
  154. package/src/components/DataTable/components/ColumnFilter.tsx +63 -74
  155. package/src/components/DataTable/components/ColumnVisibilityDropdown.tsx +43 -41
  156. package/src/components/DataTable/components/DataTableErrorBoundary.tsx +9 -11
  157. package/src/components/DataTable/components/DataTableLayout.tsx +5 -16
  158. package/src/components/DataTable/components/EditableRow.tsx +5 -7
  159. package/src/components/DataTable/components/EmptyState.tsx +11 -10
  160. package/src/components/DataTable/components/FilterRow.tsx +2 -4
  161. package/src/components/DataTable/components/ImportModal.tsx +124 -126
  162. package/src/components/DataTable/components/LoadingState.tsx +5 -6
  163. package/src/components/DataTable/components/SortIndicator.tsx +50 -0
  164. package/src/components/DataTable/components/__tests__/COVERAGE_NOTE.md +4 -4
  165. package/src/components/DataTable/components/__tests__/ColumnFilter.test.tsx +23 -82
  166. package/src/components/DataTable/components/__tests__/DataTableErrorBoundary.test.tsx +37 -9
  167. package/src/components/DataTable/components/__tests__/EmptyState.test.tsx +7 -4
  168. package/src/components/DataTable/components/__tests__/FilterRow.test.tsx +12 -4
  169. package/src/components/DataTable/components/__tests__/LoadingState.test.tsx +45 -27
  170. package/src/components/DataTable/components/index.ts +2 -1
  171. package/src/components/DataTable/types.ts +0 -18
  172. package/src/components/DataTable/utils/a11yUtils.ts +17 -0
  173. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.test.tsx +1 -1
  174. package/src/components/DatePickerWithTimezone/DatePickerWithTimezone.tsx +11 -15
  175. package/src/components/DateTimeField/DateTimeField.tsx +7 -8
  176. package/src/components/Dialog/Dialog.test.tsx +1 -0
  177. package/src/components/Dialog/Dialog.tsx +25 -8
  178. package/src/components/ErrorBoundary/ErrorBoundary.tsx +77 -79
  179. package/src/components/FileUpload/FileUpload.test.tsx +45 -16
  180. package/src/components/FileUpload/FileUpload.tsx +141 -130
  181. package/src/components/NavigationMenu/NavigationMenu.test.tsx +48 -12
  182. package/src/components/PaceAppLayout/PaceAppLayout.performance.test.tsx +9 -9
  183. package/src/components/PaceAppLayout/PaceAppLayout.security.test.tsx +30 -30
  184. package/src/components/PaceAppLayout/PaceAppLayout.test.tsx +4 -4
  185. package/src/components/PaceLoginPage/PaceLoginPage.test.tsx +7 -1
  186. package/src/components/Progress/Progress.tsx +2 -4
  187. package/src/components/ProtectedRoute/ProtectedRoute.tsx +8 -8
  188. package/src/components/Select/Select.tsx +86 -77
  189. package/src/components/Select/types.ts +3 -0
  190. package/src/hooks/__tests__/ServiceHooks.test.tsx +16 -16
  191. package/src/hooks/__tests__/hooks.integration.test.tsx +49 -49
  192. package/src/hooks/__tests__/useDataTablePerformance.unit.test.ts +8 -5
  193. package/src/hooks/__tests__/useFileUrl.unit.test.ts +4 -0
  194. package/src/hooks/__tests__/useFocusTrap.unit.test.tsx +99 -99
  195. package/src/hooks/__tests__/useInactivityTracker.unit.test.ts +45 -8
  196. package/src/hooks/__tests__/usePerformanceMonitor.unit.test.ts +22 -2
  197. package/src/hooks/public/usePublicEvent.ts +5 -5
  198. package/src/hooks/public/usePublicEventLogo.ts +5 -5
  199. package/src/hooks/public/usePublicFileDisplay.ts +2 -2
  200. package/src/hooks/public/usePublicRouteParams.ts +13 -9
  201. package/src/hooks/useAddressAutocomplete.test.ts +18 -18
  202. package/src/hooks/useAppConfig.ts +2 -2
  203. package/src/hooks/useEventTheme.test.ts +7 -7
  204. package/src/hooks/useEventTheme.ts +2 -1
  205. package/src/hooks/useFileDisplay.ts +2 -2
  206. package/src/hooks/useFileUrl.ts +52 -8
  207. package/src/hooks/useOrganisationSecurity.test.ts +2 -1
  208. package/src/providers/UnifiedAuthProvider.smoke.test.tsx +21 -21
  209. package/src/providers/__tests__/AuthProvider.test.tsx +21 -21
  210. package/src/providers/__tests__/EventProvider.test.tsx +61 -61
  211. package/src/providers/__tests__/InactivityProvider.test.tsx +56 -56
  212. package/src/providers/__tests__/OrganisationProvider.test.tsx +75 -75
  213. package/src/providers/__tests__/ProviderLifecycle.test.tsx +38 -38
  214. package/src/providers/__tests__/UnifiedAuthProvider.test.tsx +103 -103
  215. package/src/providers/services/__tests__/AuthServiceProvider.integration.test.tsx +7 -7
  216. package/src/providers/services/__tests__/UnifiedAuthProvider.integration.test.tsx +10 -10
  217. package/src/rbac/__tests__/auth-rbac.e2e.test.tsx +15 -6
  218. package/src/rbac/__tests__/rbac-functions.test.ts +3 -3
  219. package/src/rbac/api.test.ts +104 -0
  220. package/src/rbac/engine.ts +1 -1
  221. package/src/rbac/hooks/useCan.test.ts +2 -2
  222. package/src/rbac/secureClient.ts +1 -1
  223. package/src/rbac/types/functions.ts +1 -1
  224. package/src/styles/core.css +7 -0
  225. package/src/theming/__tests__/parseEventColours.test.ts +118 -3
  226. package/src/theming/parseEventColours.ts +77 -11
  227. package/src/types/supabase.ts +2 -3
  228. package/src/utils/__tests__/bundleAnalysis.unit.test.ts +9 -9
  229. package/src/utils/__tests__/lazyLoad.unit.test.tsx +42 -39
  230. package/src/utils/file-reference/__tests__/file-reference.test.ts +4 -0
  231. package/src/utils/formatting/formatDate.test.ts +3 -2
  232. package/src/utils/formatting/formatDateTime.test.ts +2 -2
  233. package/src/utils/google-places/googlePlacesUtils.test.ts +36 -24
  234. package/src/utils/storage/README.md +1 -1
  235. package/src/utils/storage/__tests__/helpers.unit.test.ts +19 -12
  236. package/src/utils/storage/helpers.test.ts +69 -3
  237. package/cursor-rules/01-standards-compliance.mdc +0 -285
  238. package/cursor-rules/04-testing-standards.mdc +0 -270
  239. package/cursor-rules/05-bug-reports-and-features.mdc +0 -248
  240. package/cursor-rules/06-code-quality.mdc +0 -311
  241. package/cursor-rules/07-tech-stack-compliance.mdc +0 -216
  242. package/cursor-rules/10-error-handling-patterns.mdc +0 -179
  243. package/cursor-rules/11-performance-optimization.mdc +0 -169
  244. package/cursor-rules/12-ci-cd-integration.mdc +0 -150
  245. package/dist/DataTable-LRJL4IRV.js +0 -15
  246. package/dist/eslint-rules/rules/compliance.cjs +0 -348
  247. package/dist/eslint-rules/rules/components.cjs +0 -113
  248. package/dist/eslint-rules/rules/imports.cjs +0 -102
  249. package/docs/best-practices/README.md +0 -472
  250. package/docs/best-practices/accessibility.md +0 -604
  251. package/docs/best-practices/common-patterns.md +0 -516
  252. package/docs/best-practices/deployment.md +0 -1103
  253. package/docs/best-practices/performance.md +0 -1328
  254. package/docs/best-practices/security.md +0 -940
  255. package/docs/best-practices/testing.md +0 -1034
  256. package/docs/rbac/compliance/compliance-guide.md +0 -544
  257. package/docs/standards/01-standards-compliance.md +0 -188
  258. package/docs/standards/03-solid-principles.md +0 -39
  259. package/docs/standards/04-testing-standards.md +0 -36
  260. package/docs/standards/05-bug-reports-and-features.md +0 -27
  261. package/docs/standards/06-code-quality.md +0 -34
  262. package/docs/standards/07-tech-stack-compliance.md +0 -30
  263. package/docs/standards/10-error-handling-patterns.md +0 -401
  264. package/docs/standards/11-performance-optimization.md +0 -348
  265. package/docs/standards/12-ci-cd-integration.md +0 -370
  266. package/docs/standards/ALIGNMENT_REVIEW_SUMMARY.md +0 -192
  267. package/scripts/audit/audit-compliance.cjs +0 -1295
  268. package/scripts/audit/audit-components.cjs +0 -260
  269. package/scripts/audit/audit-rbac.cjs +0 -954
  270. package/scripts/audit/audit-standards.cjs +0 -1268
  271. package/scripts/audit/index.cjs +0 -1927
  272. package/src/components/DataTable/components/DataTableBody.tsx +0 -478
  273. package/src/components/DataTable/components/DraggableColumnHeader.tsx +0 -156
  274. package/src/components/DataTable/components/ExpandButton.tsx +0 -113
  275. package/src/components/DataTable/components/GroupHeader.tsx +0 -54
  276. package/src/components/DataTable/components/ViewRowModal.tsx +0 -68
  277. package/src/components/DataTable/components/VirtualizedDataTable.tsx +0 -525
  278. package/src/components/DataTable/components/__tests__/ExpandButton.test.tsx +0 -462
  279. package/src/components/DataTable/components/__tests__/GroupHeader.test.tsx +0 -393
  280. package/src/components/DataTable/components/__tests__/ViewRowModal.test.tsx +0 -476
  281. package/src/components/DataTable/components/__tests__/VirtualizedDataTable.test.tsx +0 -128
  282. package/src/components/DataTable/core/DataTableContext.tsx +0 -216
  283. package/src/components/DataTable/core/__tests__/DataTableContext.test.tsx +0 -136
  284. package/src/components/DataTable/hooks/__tests__/useColumnReordering.test.ts +0 -570
  285. package/src/components/DataTable/hooks/useColumnReordering.ts +0 -123
  286. package/src/components/DataTable/utils/debugTools.ts +0 -514
  287. package/src/eslint-rules/index.cjs +0 -22
  288. package/src/eslint-rules/rules/components.cjs +0 -113
  289. package/src/eslint-rules/rules/imports.cjs +0 -102
  290. package/src/eslint-rules/rules/rbac.cjs +0 -790
  291. package/src/eslint-rules/utils/helpers.cjs +0 -42
  292. package/src/eslint-rules/utils/manifest-loader.cjs +0 -75
@@ -1,401 +0,0 @@
1
- # Error Handling Patterns
2
-
3
- **🤖 Cursor Rule**: See [10-error-handling-patterns.mdc](../../cursor-rules/10-error-handling-patterns.mdc) for AI-optimized directives that automatically enforce error handling patterns.
4
-
5
- ## Purpose
6
-
7
- This standard defines consistent error handling patterns across pace-core and consuming apps to ensure:
8
- - **User-friendly error messages** that don't expose internal details
9
- - **Type-safe error handling** with proper TypeScript types
10
- - **Consistent error recovery** strategies
11
- - **Proper error logging** without exposing sensitive data
12
- - **Graceful degradation** when errors occur
13
-
14
- ## Principles
15
-
16
- 1. **Never expose internal details** in user-facing error messages
17
- 2. **Always use type-safe error handling** (no `any` types)
18
- 3. **Log errors appropriately** (with context, without sensitive data)
19
- 4. **Provide recovery paths** when possible
20
- 5. **Use consistent error shapes** across the application
21
-
22
- ## Error Types
23
-
24
- ### API Errors
25
-
26
- **Shape:**
27
- ```typescript
28
- type ApiError = {
29
- ok: false;
30
- error: {
31
- code: string; // Machine-readable error code
32
- message: string; // User-friendly message
33
- details?: object; // Optional additional context (non-sensitive)
34
- };
35
- };
36
- ```
37
-
38
- **Example:**
39
- ```typescript
40
- // ✅ CORRECT
41
- const result = await apiCall();
42
- if (!result.ok) {
43
- // result.error.message is user-friendly
44
- toast.error(result.error.message);
45
- logger.error('API call failed', { code: result.error.code, details: result.error.details });
46
- }
47
-
48
- // ❌ WRONG - Exposing internal details
49
- if (error.message.includes('SQL')) {
50
- toast.error(error.message); // Exposes database internals
51
- }
52
- ```
53
-
54
- ### Validation Errors
55
-
56
- **Shape:**
57
- ```typescript
58
- type ValidationError = {
59
- field: string;
60
- message: string;
61
- code?: string;
62
- };
63
- ```
64
-
65
- **Example:**
66
- ```typescript
67
- // ✅ CORRECT - Using Zod validation
68
- const schema = z.object({
69
- email: z.string().email('Please enter a valid email address'),
70
- name: z.string().min(1, 'Name is required'),
71
- });
72
-
73
- try {
74
- const data = schema.parse(formData);
75
- } catch (error) {
76
- if (error instanceof z.ZodError) {
77
- // User-friendly validation messages
78
- error.errors.forEach(err => {
79
- toast.error(err.message);
80
- });
81
- }
82
- }
83
- ```
84
-
85
- ### Network Errors
86
-
87
- **Pattern:**
88
- ```typescript
89
- // ✅ CORRECT - Handle network errors gracefully
90
- try {
91
- const data = await fetchData();
92
- } catch (error) {
93
- if (error instanceof TypeError && error.message.includes('fetch')) {
94
- toast.error('Unable to connect. Please check your internet connection.');
95
- logger.error('Network error', { error: error.message });
96
- } else {
97
- toast.error('An unexpected error occurred. Please try again.');
98
- logger.error('Unexpected error', { error });
99
- }
100
- }
101
- ```
102
-
103
- ## Error Handling Patterns
104
-
105
- ### Pattern 1: Try-Catch with Type Guards
106
-
107
- **Use for:** Known error types that need different handling
108
-
109
- ```typescript
110
- // ✅ CORRECT
111
- function isApiError(error: unknown): error is ApiError {
112
- return (
113
- typeof error === 'object' &&
114
- error !== null &&
115
- 'ok' in error &&
116
- (error as ApiError).ok === false &&
117
- 'error' in error
118
- );
119
- }
120
-
121
- try {
122
- const result = await apiCall();
123
- if (!result.ok) {
124
- handleApiError(result.error);
125
- }
126
- } catch (error) {
127
- if (isApiError(error)) {
128
- handleApiError(error.error);
129
- } else {
130
- handleUnknownError(error);
131
- }
132
- }
133
- ```
134
-
135
- ### Pattern 2: Result Types
136
-
137
- **Use for:** Functions that can fail (preferred pattern)
138
-
139
- ```typescript
140
- // ✅ CORRECT - Using Result type
141
- type Result<T, E = ApiError> =
142
- | { ok: true; data: T }
143
- | { ok: false; error: E };
144
-
145
- async function fetchUser(id: string): Promise<Result<User>> {
146
- try {
147
- const { data, error } = await supabase.from('users').select('*').eq('id', id).single();
148
- if (error) {
149
- return { ok: false, error: { code: 'USER_NOT_FOUND', message: 'User not found' } };
150
- }
151
- return { ok: true, data };
152
- } catch (error) {
153
- return {
154
- ok: false,
155
- error: { code: 'UNKNOWN_ERROR', message: 'An unexpected error occurred' }
156
- };
157
- }
158
- }
159
-
160
- // Usage
161
- const result = await fetchUser(userId);
162
- if (result.ok) {
163
- // TypeScript knows result.data exists
164
- setUser(result.data);
165
- } else {
166
- // TypeScript knows result.error exists
167
- toast.error(result.error.message);
168
- }
169
- ```
170
-
171
- ### Pattern 3: Error Boundaries (React)
172
-
173
- **Use for:** Catching React component errors
174
-
175
- ```tsx
176
- // ✅ CORRECT - Error boundary component
177
- import { ErrorBoundary } from '@jmruthers/pace-core';
178
-
179
- function App() {
180
- return (
181
- <ErrorBoundary
182
- fallback={<ErrorFallback />}
183
- onError={(error, errorInfo) => {
184
- logger.error('React error boundary caught error', { error, errorInfo });
185
- }}
186
- >
187
- <YourApp />
188
- </ErrorBoundary>
189
- );
190
- }
191
- ```
192
-
193
- ### Pattern 4: Async Error Handling
194
-
195
- **Use for:** Async operations with proper error handling
196
-
197
- ```typescript
198
- // ✅ CORRECT - Async with error handling
199
- async function loadData() {
200
- try {
201
- setIsLoading(true);
202
- const result = await fetchData();
203
- if (!result.ok) {
204
- throw new Error(result.error.message);
205
- }
206
- setData(result.data);
207
- } catch (error) {
208
- handleError(error);
209
- } finally {
210
- setIsLoading(false);
211
- }
212
- }
213
- ```
214
-
215
- ## Error Messages
216
-
217
- ### User-Facing Messages
218
-
219
- **MUST:**
220
- - Be user-friendly and actionable
221
- - Not expose internal details (SQL, stack traces, file paths)
222
- - Provide context when helpful
223
- - Be consistent in tone and style
224
-
225
- **Examples:**
226
- ```typescript
227
- // ✅ CORRECT - User-friendly
228
- 'Unable to save changes. Please try again.'
229
- 'This field is required.'
230
- 'Invalid email address format.'
231
-
232
- // ❌ WRONG - Exposes internals
233
- 'SQLSTATE[23000]: Integrity constraint violation'
234
- 'Cannot read property "data" of undefined'
235
- '/app/src/services/api.ts:123:45'
236
- ```
237
-
238
- ### Logging Messages
239
-
240
- **MUST:**
241
- - Include error context (user ID, operation, etc.)
242
- - Not log sensitive data (passwords, tokens, PII)
243
- - Use structured logging when possible
244
- - Include error codes for correlation
245
-
246
- **Examples:**
247
- ```typescript
248
- // ✅ CORRECT - Structured logging
249
- logger.error('Failed to save user', {
250
- userId: user.id,
251
- operation: 'updateUser',
252
- errorCode: error.code,
253
- timestamp: new Date().toISOString(),
254
- });
255
-
256
- // ❌ WRONG - Logs sensitive data
257
- logger.error('Failed to save user', {
258
- password: user.password, // NEVER log passwords
259
- token: authToken, // NEVER log tokens
260
- ssn: user.ssn, // NEVER log PII
261
- });
262
- ```
263
-
264
- ## Error Recovery
265
-
266
- ### Retry Logic
267
-
268
- **Use for:** Transient errors (network, timeouts)
269
-
270
- ```typescript
271
- // ✅ CORRECT - Retry with exponential backoff
272
- async function fetchWithRetry<T>(
273
- fn: () => Promise<Result<T>>,
274
- maxRetries = 3
275
- ): Promise<Result<T>> {
276
- for (let attempt = 0; attempt < maxRetries; attempt++) {
277
- const result = await fn();
278
- if (result.ok) {
279
- return result;
280
- }
281
-
282
- // Don't retry on client errors (4xx)
283
- if (result.error.code?.startsWith('4')) {
284
- return result;
285
- }
286
-
287
- // Exponential backoff
288
- await new Promise(resolve => setTimeout(resolve, Math.pow(2, attempt) * 1000));
289
- }
290
-
291
- return { ok: false, error: { code: 'MAX_RETRIES', message: 'Operation failed after retries' } };
292
- }
293
- ```
294
-
295
- ### Fallback Values
296
-
297
- **Use for:** Non-critical data that can have defaults
298
-
299
- ```typescript
300
- // ✅ CORRECT - Fallback to default
301
- const userPreferences = await fetchUserPreferences().catch(() => ({
302
- theme: 'light',
303
- language: 'en',
304
- }));
305
- ```
306
-
307
- ### Graceful Degradation
308
-
309
- **Use for:** Features that can work without optional data
310
-
311
- ```typescript
312
- // ✅ CORRECT - Graceful degradation
313
- async function loadDashboard() {
314
- const [events, stats, preferences] = await Promise.allSettled([
315
- fetchEvents(),
316
- fetchStats(),
317
- fetchPreferences(),
318
- ]);
319
-
320
- // Use data that loaded successfully
321
- if (events.status === 'fulfilled') {
322
- setEvents(events.value);
323
- } else {
324
- logger.warn('Events failed to load', events.reason);
325
- setEvents([]); // Fallback to empty array
326
- }
327
-
328
- // Similar for stats and preferences
329
- }
330
- ```
331
-
332
- ## Error Handling Checklist
333
-
334
- Before committing code with error handling, verify:
335
-
336
- - [ ] User-facing error messages are friendly and actionable
337
- - [ ] No internal details exposed in user messages
338
- - [ ] Type-safe error handling (no `any` types)
339
- - [ ] Errors are logged with context (no sensitive data)
340
- - [ ] Recovery paths provided when possible
341
- - [ ] Error shapes are consistent
342
- - [ ] Error boundaries used for React components
343
- - [ ] Async operations have proper error handling
344
- - [ ] Validation errors use Zod or similar
345
- - [ ] Network errors handled gracefully
346
-
347
- ## Common Mistakes to Avoid
348
-
349
- ### ❌ Don't: Expose Internal Details
350
-
351
- ```typescript
352
- // ❌ WRONG
353
- toast.error(error.message); // May contain SQL, stack traces, etc.
354
- ```
355
-
356
- ### ❌ Don't: Use `any` for Errors
357
-
358
- ```typescript
359
- // ❌ WRONG
360
- catch (error: any) {
361
- console.log(error.message);
362
- }
363
- ```
364
-
365
- ### ❌ Don't: Log Sensitive Data
366
-
367
- ```typescript
368
- // ❌ WRONG
369
- logger.error('Login failed', { password, token });
370
- ```
371
-
372
- ### ❌ Don't: Ignore Errors
373
-
374
- ```typescript
375
- // ❌ WRONG
376
- try {
377
- await riskyOperation();
378
- } catch (error) {
379
- // Silent failure - user has no idea what happened
380
- }
381
- ```
382
-
383
- ### ❌ Don't: Use Generic Messages
384
-
385
- ```typescript
386
- // ❌ WRONG
387
- toast.error('Error occurred'); // Not helpful
388
- ```
389
-
390
- ## Related Documentation
391
-
392
- - [Code Quality Standard](./06-code-quality.md) - TypeScript and code style standards
393
- - [Security Standard](./01-standards-compliance.md#security-standard) - Security requirements
394
- - [API & RPC Standard](./01-standards-compliance.md#api--rpc-standard) - API error shapes
395
-
396
- ---
397
-
398
- **Last Updated:** 2025-01-28
399
- **Version:** 1.0.0
400
- **Applies to:** All pace-core and consuming apps
401
-