4.1 KiB
4.1 KiB
Tasks: enterprise-react-error-boundary
Change ID: enterprise-react-error-boundary
Package: @suaveplan/react-error-boundary
Target path: react/ui/react-error-boundary
Prerequisite packages on Verdaccio: @suaveplan/error, @suaveplan/react-translate
0. Pre-flight (non-negotiable)
- 0.1 Confirm clean working tree (
git statusreports nothing) and no in-flight worktrees with uncommitted work (git worktree listthengit statusin each) - 0.2 If any worktrees exist under
.claude/worktrees/, account for each one: still-active agent, work-pending-merge, or stale-and-prune. Stale worktrees MUST be removed (git worktree remove) before opening a new one — code that has been lost twice on main is the failure mode this guards against. - 0.3 Confirm the package set in
MANIFEST.mdmatchesfind packages -maxdepth 3 -name package.jsoncount. Drift here means a prior change archived without regenerating the manifest.
1. Scaffold
- Create directory tree per proposal layout.
- Write
package.jsonat0.1.0with"sideEffects": false, exports map. - Dependencies:
@suaveplan/error workspace:^,@suaveplan/react-translate workspace:^,@opentelemetry/api catalog:observability,tslib catalog:build. - Write
tsconfig.json,vitest.config.ts, scripts.
2. Types
- Define
FallbackProps:{ error: Error; resetErrorBoundary: () => void }. - Define
ErrorBoundaryProps:children,fallback?: ReactNode,FallbackComponent?: ComponentType<FallbackProps>,onError?: (error, info) => void,onReset?: () => void,resetKeys?: unknown[]. - Define
ErrorBoundaryState:{ hasError: boolean; error: Error | null }. - Define
UseErrorBoundaryReturn:{ showBoundary: (error: Error) => void }.
3. DefaultFallback
- Renders translated "Something went wrong" heading + error message (dev-only) + "Try again" button calling
resetErrorBoundary. - Uses
useTranslationfrom@suaveplan/react-translate. - Write
default-fallback.test.tsx: renders heading, button calls reset.{ timeout: 5000 }. - Write
default-fallback.stories.tsx: default, with-error-message, playground. - Write
default-fallback.md.
4. ErrorBoundary
- Class component with
static getDerivedStateFromError(error)andcomponentDidCatch(error, info). componentDidCatch— callsthis.props.onError(error, info); emits OTel span eventerror_boundary.caughtwith attributeserror.message,error.type, anderror.code(iferror instanceof SuaveplanError).resetKeyswatching viacomponentDidUpdate— if anyresetKeys[i]changed value, callreset().- Renders
FallbackComponentif provided, elsefallbackprop, elseDefaultFallback. - Write
error-boundary.test.tsx: catch + fallback rendered, reset clears error, onError called, onReset called, resetKeys trigger reset, FallbackComponent receives props.{ timeout: 5000 }. - Write
error-boundary.stories.tsx: default (forced throw), custom FallbackComponent, resetKeys, playground. - Write
error-boundary.md(≥200 words).
5. useErrorBoundary hook
- Uses
useStateto hold a thrown error; throws it in render viauseEffect→ nearest boundary catches it. - Returns
{ showBoundary: (error: Error) => void }. - Write
use-error-boundary.test.tsx: callingshowBoundarycauses boundary to catch.{ timeout: 5000 }. - Write
use-error-boundary.stories.tsx: playground (button callsshowBoundary). - Write
use-error-boundary.md.
6. E2E
e2e/error-boundary.spec.ts— Playwright:- Render component that throws on click →
DefaultFallbackshown. - Click "Try again" → component re-mounts without error.
FallbackComponentrenders with correcterror.message.
- Render component that throws on click →
7. Verify and publish
bunx turbo lint typecheck test --filter=@suaveplan/react-error-boundary— green.bunx turbo test:coverage --filter=@suaveplan/react-error-boundary— 100%.bun scripts/publish.ts --package @suaveplan/react-error-boundary.- Archive change folder.