@aicgen/aicgen 1.0.0-beta.1
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.
- package/.claude/agents/architecture-reviewer.md +88 -0
- package/.claude/agents/guideline-checker.md +73 -0
- package/.claude/agents/security-auditor.md +108 -0
- package/.claude/guidelines/api-design.md +645 -0
- package/.claude/guidelines/architecture.md +2503 -0
- package/.claude/guidelines/best-practices.md +618 -0
- package/.claude/guidelines/code-style.md +304 -0
- package/.claude/guidelines/design-patterns.md +573 -0
- package/.claude/guidelines/devops.md +226 -0
- package/.claude/guidelines/error-handling.md +413 -0
- package/.claude/guidelines/language.md +782 -0
- package/.claude/guidelines/performance.md +706 -0
- package/.claude/guidelines/security.md +583 -0
- package/.claude/guidelines/testing.md +568 -0
- package/.claude/settings.json +98 -0
- package/.claude/settings.local.json +8 -0
- package/.env.example +23 -0
- package/.eslintrc.json +28 -0
- package/.github/workflows/release.yml +180 -0
- package/.github/workflows/test.yml +81 -0
- package/.gitmodules +3 -0
- package/.vs/ProjectSettings.json +3 -0
- package/.vs/VSWorkspaceState.json +16 -0
- package/.vs/aicgen.slnx/FileContentIndex/5f0ce2a3-fd68-4863-9e23-e428cf1794e3.vsidx +0 -0
- package/.vs/aicgen.slnx/v18/.wsuo +0 -0
- package/.vs/aicgen.slnx/v18/DocumentLayout.json +54 -0
- package/.vs/slnx.sqlite +0 -0
- package/AGENTS.md +121 -0
- package/CLAUDE.md +36 -0
- package/CONTRIBUTING.md +821 -0
- package/LICENSE +21 -0
- package/README.md +199 -0
- package/assets/icon.svg +34 -0
- package/assets/logo.svg +41 -0
- package/bun.lock +848 -0
- package/data/LICENSE +21 -0
- package/data/README.md +203 -0
- package/data/api/basics.md +292 -0
- package/data/api/index.md +8 -0
- package/data/api/pagination.md +142 -0
- package/data/api/rest.md +137 -0
- package/data/api/versioning.md +60 -0
- package/data/architecture/clean-architecture/index.md +7 -0
- package/data/architecture/clean-architecture/layers.md +111 -0
- package/data/architecture/ddd/index.md +8 -0
- package/data/architecture/ddd/strategic.md +89 -0
- package/data/architecture/ddd/tactical.md +132 -0
- package/data/architecture/event-driven/index.md +7 -0
- package/data/architecture/event-driven/messaging.md +242 -0
- package/data/architecture/event-driven/patterns.md +129 -0
- package/data/architecture/feature-toggles/index.md +7 -0
- package/data/architecture/feature-toggles/patterns.md +73 -0
- package/data/architecture/gui/index.md +7 -0
- package/data/architecture/gui/patterns.md +132 -0
- package/data/architecture/hexagonal/ports-adapters.md +132 -0
- package/data/architecture/index.md +12 -0
- package/data/architecture/layered/index.md +7 -0
- package/data/architecture/layered/layers.md +100 -0
- package/data/architecture/microservices/api-gateway.md +56 -0
- package/data/architecture/microservices/boundaries.md +80 -0
- package/data/architecture/microservices/communication.md +97 -0
- package/data/architecture/microservices/data.md +92 -0
- package/data/architecture/microservices/index.md +11 -0
- package/data/architecture/microservices/resilience.md +111 -0
- package/data/architecture/modular-monolith/boundaries.md +133 -0
- package/data/architecture/modular-monolith/structure.md +131 -0
- package/data/architecture/serverless/best-practices.md +322 -0
- package/data/architecture/serverless/index.md +7 -0
- package/data/architecture/serverless/patterns.md +80 -0
- package/data/architecture/solid/index.md +7 -0
- package/data/architecture/solid/principles.md +187 -0
- package/data/database/basics.md +365 -0
- package/data/database/design-patterns.md +68 -0
- package/data/database/index.md +8 -0
- package/data/database/indexing.md +136 -0
- package/data/database/nosql.md +223 -0
- package/data/database/schema.md +137 -0
- package/data/devops/ci-cd.md +66 -0
- package/data/devops/index.md +8 -0
- package/data/devops/observability.md +73 -0
- package/data/devops/practices.md +77 -0
- package/data/error-handling/basics.md +222 -0
- package/data/error-handling/index.md +7 -0
- package/data/error-handling/strategy.md +185 -0
- package/data/guideline-mappings.yml +1077 -0
- package/data/index.md +3 -0
- package/data/language/csharp/basics.md +210 -0
- package/data/language/csharp/testing.md +252 -0
- package/data/language/go/basics.md +158 -0
- package/data/language/go/testing.md +192 -0
- package/data/language/index.md +14 -0
- package/data/language/java/basics.md +184 -0
- package/data/language/java/testing.md +273 -0
- package/data/language/javascript/basics.md +217 -0
- package/data/language/javascript/testing.md +269 -0
- package/data/language/python/async.md +100 -0
- package/data/language/python/basics.md +100 -0
- package/data/language/python/index.md +10 -0
- package/data/language/python/testing.md +125 -0
- package/data/language/python/types.md +99 -0
- package/data/language/ruby/basics.md +227 -0
- package/data/language/ruby/testing.md +267 -0
- package/data/language/rust/basics.md +175 -0
- package/data/language/rust/testing.md +219 -0
- package/data/language/typescript/async.md +103 -0
- package/data/language/typescript/basics.md +87 -0
- package/data/language/typescript/config.md +95 -0
- package/data/language/typescript/error-handling.md +98 -0
- package/data/language/typescript/generics.md +85 -0
- package/data/language/typescript/index.md +14 -0
- package/data/language/typescript/interfaces-types.md +83 -0
- package/data/language/typescript/performance.md +103 -0
- package/data/language/typescript/testing.md +98 -0
- package/data/patterns/base-patterns.md +105 -0
- package/data/patterns/concurrency.md +87 -0
- package/data/patterns/data-access.md +83 -0
- package/data/patterns/distribution.md +86 -0
- package/data/patterns/domain-logic.md +81 -0
- package/data/patterns/gof.md +109 -0
- package/data/patterns/index.md +12 -0
- package/data/performance/async.md +148 -0
- package/data/performance/basics.md +324 -0
- package/data/performance/caching-strategies.md +68 -0
- package/data/performance/caching.md +152 -0
- package/data/performance/index.md +8 -0
- package/data/practices/code-review.md +52 -0
- package/data/practices/documentation.md +260 -0
- package/data/practices/index.md +11 -0
- package/data/practices/planning.md +142 -0
- package/data/practices/refactoring.md +91 -0
- package/data/practices/version-control.md +55 -0
- package/data/security/auth-jwt.md +159 -0
- package/data/security/headers.md +143 -0
- package/data/security/index.md +10 -0
- package/data/security/injection.md +119 -0
- package/data/security/secrets.md +148 -0
- package/data/style/index.md +8 -0
- package/data/style/naming.md +136 -0
- package/data/style/organization.md +162 -0
- package/data/templates/agents/architecture-reviewer.md +88 -0
- package/data/templates/agents/guideline-checker.md +73 -0
- package/data/templates/agents/security-auditor.md +108 -0
- package/data/templates/antigravity/rules/architecture.md.hbs +5 -0
- package/data/templates/antigravity/rules/code-style.md.hbs +5 -0
- package/data/templates/antigravity/rules/language.md.hbs +5 -0
- package/data/templates/antigravity/rules/performance.md.hbs +5 -0
- package/data/templates/antigravity/rules/security.md.hbs +5 -0
- package/data/templates/antigravity/rules/testing.md.hbs +5 -0
- package/data/templates/antigravity/workflows/add-documentation.md.hbs +23 -0
- package/data/templates/antigravity/workflows/generate-integration-tests.md.hbs +17 -0
- package/data/templates/antigravity/workflows/generate-unit-tests.md.hbs +20 -0
- package/data/templates/antigravity/workflows/performance-audit.md.hbs +24 -0
- package/data/templates/antigravity/workflows/refactor-extract-module.md.hbs +17 -0
- package/data/templates/antigravity/workflows/security-audit.md.hbs +20 -0
- package/data/templates/hooks/formatting.json +26 -0
- package/data/templates/hooks/security.json +35 -0
- package/data/templates/hooks/testing.json +17 -0
- package/data/testing/basics.md +151 -0
- package/data/testing/index.md +9 -0
- package/data/testing/integration.md +159 -0
- package/data/testing/unit-fundamentals.md +128 -0
- package/data/testing/unit-mocking.md +116 -0
- package/data/version.json +49 -0
- package/dist/commands/init.d.ts +8 -0
- package/dist/commands/init.d.ts.map +1 -0
- package/dist/commands/init.js +46 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/config/profiles.d.ts +4 -0
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/profiles.js +30 -0
- package/dist/config/profiles.js.map +1 -0
- package/dist/config/settings.d.ts +7 -0
- package/dist/config/settings.d.ts.map +1 -0
- package/dist/config/settings.js +7 -0
- package/dist/config/settings.js.map +1 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +58489 -0
- package/dist/index.js.map +1 -0
- package/dist/models/guideline.d.ts +15 -0
- package/dist/models/guideline.d.ts.map +1 -0
- package/dist/models/guideline.js +2 -0
- package/dist/models/guideline.js.map +1 -0
- package/dist/models/preference.d.ts +9 -0
- package/dist/models/preference.d.ts.map +1 -0
- package/dist/models/preference.js +2 -0
- package/dist/models/preference.js.map +1 -0
- package/dist/models/profile.d.ts +9 -0
- package/dist/models/profile.d.ts.map +1 -0
- package/dist/models/profile.js +2 -0
- package/dist/models/profile.js.map +1 -0
- package/dist/models/project.d.ts +13 -0
- package/dist/models/project.d.ts.map +1 -0
- package/dist/models/project.js +2 -0
- package/dist/models/project.js.map +1 -0
- package/dist/services/ai/anthropic.d.ts +7 -0
- package/dist/services/ai/anthropic.d.ts.map +1 -0
- package/dist/services/ai/anthropic.js +39 -0
- package/dist/services/ai/anthropic.js.map +1 -0
- package/dist/services/generator.d.ts +2 -0
- package/dist/services/generator.d.ts.map +1 -0
- package/dist/services/generator.js +4 -0
- package/dist/services/generator.js.map +1 -0
- package/dist/services/learner.d.ts +2 -0
- package/dist/services/learner.d.ts.map +1 -0
- package/dist/services/learner.js +4 -0
- package/dist/services/learner.js.map +1 -0
- package/dist/services/scanner.d.ts +3 -0
- package/dist/services/scanner.d.ts.map +1 -0
- package/dist/services/scanner.js +54 -0
- package/dist/services/scanner.js.map +1 -0
- package/dist/utils/errors.d.ts +15 -0
- package/dist/utils/errors.d.ts.map +1 -0
- package/dist/utils/errors.js +27 -0
- package/dist/utils/errors.js.map +1 -0
- package/dist/utils/file.d.ts +7 -0
- package/dist/utils/file.d.ts.map +1 -0
- package/dist/utils/file.js +32 -0
- package/dist/utils/file.js.map +1 -0
- package/dist/utils/logger.d.ts +6 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/path.d.ts +6 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +14 -0
- package/dist/utils/path.js.map +1 -0
- package/docs/planning/memory-lane.md +83 -0
- package/package.json +64 -0
- package/packaging/linux/aicgen.spec +23 -0
- package/packaging/linux/control +9 -0
- package/packaging/macos/scripts/postinstall +12 -0
- package/packaging/windows/setup.nsi +92 -0
- package/planning/BRANDING-SUMMARY.md +194 -0
- package/planning/BRANDING.md +174 -0
- package/planning/BUILD.md +186 -0
- package/planning/CHUNK-IMPLEMENTATION-PLAN.md +87 -0
- package/planning/CHUNK-TAXONOMY.md +375 -0
- package/planning/CHUNKS-COMPLETE.md +382 -0
- package/planning/DESIGN.md +313 -0
- package/planning/DYNAMIC-GUIDELINES-DESIGN.md +265 -0
- package/planning/ENTERPRISE-UX-COMPLETE.md +281 -0
- package/planning/IMPLEMENTATION-PLAN.md +20 -0
- package/planning/PHASE1-COMPLETE.md +211 -0
- package/planning/PHASE2-COMPLETE.md +350 -0
- package/planning/PHASE3-COMPLETE.md +399 -0
- package/planning/PHASE4-COMPLETE.md +361 -0
- package/planning/PHASE4.5-CHUNKS.md +462 -0
- package/planning/STRUCTURE.md +170 -0
- package/scripts/add-categories.ts +87 -0
- package/scripts/build-binary.ts +46 -0
- package/scripts/embed-data.ts +105 -0
- package/scripts/generate-version.ts +150 -0
- package/scripts/test-decompress.ts +27 -0
- package/scripts/test-extract.ts +31 -0
- package/src/__tests__/services/assistant-file-writer.test.ts +400 -0
- package/src/__tests__/services/guideline-loader.test.ts +281 -0
- package/src/__tests__/services/tarball-extraction.test.ts +125 -0
- package/src/commands/add-guideline.ts +296 -0
- package/src/commands/clear.ts +61 -0
- package/src/commands/guideline-selector.ts +123 -0
- package/src/commands/init.ts +645 -0
- package/src/commands/quick-add.ts +586 -0
- package/src/commands/remove-guideline.ts +152 -0
- package/src/commands/stats.ts +49 -0
- package/src/commands/update.ts +240 -0
- package/src/config.ts +82 -0
- package/src/embedded-data.ts +1492 -0
- package/src/index.ts +67 -0
- package/src/models/profile.ts +24 -0
- package/src/models/project.ts +43 -0
- package/src/services/assistant-file-writer.ts +612 -0
- package/src/services/config-generator.ts +150 -0
- package/src/services/config-manager.ts +70 -0
- package/src/services/data-source.ts +248 -0
- package/src/services/first-run-init.ts +148 -0
- package/src/services/guideline-loader.ts +311 -0
- package/src/services/hook-generator.ts +178 -0
- package/src/services/subagent-generator.ts +310 -0
- package/src/utils/banner.ts +66 -0
- package/src/utils/errors.ts +27 -0
- package/src/utils/file.ts +67 -0
- package/src/utils/formatting.ts +172 -0
- package/src/utils/logger.ts +89 -0
- package/src/utils/path.ts +17 -0
- package/src/utils/wizard-state.ts +132 -0
- package/tsconfig.json +25 -0
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# Error Handling Basics
|
|
2
|
+
|
|
3
|
+
## Throwing Errors
|
|
4
|
+
|
|
5
|
+
Use `throw` to signal when something goes wrong.
|
|
6
|
+
|
|
7
|
+
```pseudocode
|
|
8
|
+
function divide(a, b):
|
|
9
|
+
if b == 0:
|
|
10
|
+
throw Error("Cannot divide by zero")
|
|
11
|
+
return a / b
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Try-Catch
|
|
15
|
+
|
|
16
|
+
Use `try-catch` to handle errors gracefully.
|
|
17
|
+
|
|
18
|
+
```pseudocode
|
|
19
|
+
try:
|
|
20
|
+
result = divide(10, 0)
|
|
21
|
+
print(result)
|
|
22
|
+
catch error:
|
|
23
|
+
print("Error:", error.message)
|
|
24
|
+
// Continue with fallback behavior
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Always Provide Error Messages
|
|
28
|
+
|
|
29
|
+
Make error messages clear and actionable.
|
|
30
|
+
|
|
31
|
+
```pseudocode
|
|
32
|
+
// ❌ Bad: Vague error
|
|
33
|
+
throw Error("Invalid")
|
|
34
|
+
|
|
35
|
+
// ✅ Good: Specific error
|
|
36
|
+
throw Error("Email must be a valid email address")
|
|
37
|
+
|
|
38
|
+
// ✅ Good: Include context
|
|
39
|
+
throw Error("User with ID " + userId + " not found")
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Async Error Handling
|
|
43
|
+
|
|
44
|
+
Always use try-catch with async operations.
|
|
45
|
+
|
|
46
|
+
```pseudocode
|
|
47
|
+
async function loadUser(id):
|
|
48
|
+
try:
|
|
49
|
+
user = await fetchUser(id)
|
|
50
|
+
return user
|
|
51
|
+
catch error:
|
|
52
|
+
log("Failed to load user:", error)
|
|
53
|
+
throw error // Re-throw if caller should know
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## When to Catch Errors
|
|
57
|
+
|
|
58
|
+
### Catch When You Can Handle It
|
|
59
|
+
|
|
60
|
+
```pseudocode
|
|
61
|
+
// ✅ Good: Can provide fallback
|
|
62
|
+
async function getUserName(id):
|
|
63
|
+
try:
|
|
64
|
+
user = await fetchUser(id)
|
|
65
|
+
return user.name
|
|
66
|
+
catch error:
|
|
67
|
+
return "Unknown User" // Fallback value
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Don't Catch If You Can't Handle
|
|
71
|
+
|
|
72
|
+
```pseudocode
|
|
73
|
+
// ❌ Bad: Catching but doing nothing
|
|
74
|
+
try:
|
|
75
|
+
await criticalOperation()
|
|
76
|
+
catch error:
|
|
77
|
+
// Empty catch - error lost!
|
|
78
|
+
|
|
79
|
+
// ✅ Good: Let it propagate
|
|
80
|
+
await criticalOperation() // Caller will handle
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
## Validate Input Early
|
|
84
|
+
|
|
85
|
+
Check for problems before they cause errors.
|
|
86
|
+
|
|
87
|
+
```pseudocode
|
|
88
|
+
function createUser(email, age):
|
|
89
|
+
// Validate inputs first
|
|
90
|
+
if email is empty:
|
|
91
|
+
throw Error("Email is required")
|
|
92
|
+
|
|
93
|
+
if not email.contains("@"):
|
|
94
|
+
throw Error("Email must be valid")
|
|
95
|
+
|
|
96
|
+
if age < 0:
|
|
97
|
+
throw Error("Age cannot be negative")
|
|
98
|
+
|
|
99
|
+
// Now proceed with creation
|
|
100
|
+
return { email: email, age: age }
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Logging Errors
|
|
104
|
+
|
|
105
|
+
Always log errors for debugging.
|
|
106
|
+
|
|
107
|
+
```pseudocode
|
|
108
|
+
try:
|
|
109
|
+
await processPayment(orderId)
|
|
110
|
+
catch error:
|
|
111
|
+
// Log with context
|
|
112
|
+
log("Payment processing failed:", {
|
|
113
|
+
orderId: orderId,
|
|
114
|
+
error: error.message,
|
|
115
|
+
timestamp: currentTime()
|
|
116
|
+
})
|
|
117
|
+
throw error
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Error Handling Patterns
|
|
121
|
+
|
|
122
|
+
### Return Error Status
|
|
123
|
+
|
|
124
|
+
```pseudocode
|
|
125
|
+
function parseNumber(input):
|
|
126
|
+
num = parseInt(input)
|
|
127
|
+
if isNaN(num):
|
|
128
|
+
return null // Indicate failure without throwing
|
|
129
|
+
return num
|
|
130
|
+
|
|
131
|
+
// Usage
|
|
132
|
+
result = parseNumber(userInput)
|
|
133
|
+
if result is null:
|
|
134
|
+
print("Invalid number")
|
|
135
|
+
else:
|
|
136
|
+
print("Number:", result)
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
### Return Success/Error Object
|
|
140
|
+
|
|
141
|
+
```pseudocode
|
|
142
|
+
function safeDivide(a, b):
|
|
143
|
+
if b == 0:
|
|
144
|
+
return { success: false, error: "Cannot divide by zero" }
|
|
145
|
+
return { success: true, data: a / b }
|
|
146
|
+
|
|
147
|
+
// Usage
|
|
148
|
+
result = safeDivide(10, 2)
|
|
149
|
+
if result.success:
|
|
150
|
+
print("Result:", result.data)
|
|
151
|
+
else:
|
|
152
|
+
print("Error:", result.error)
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
## Common Mistakes
|
|
156
|
+
|
|
157
|
+
### Don't Swallow Errors
|
|
158
|
+
|
|
159
|
+
```pseudocode
|
|
160
|
+
// ❌ Bad: Error disappears
|
|
161
|
+
try:
|
|
162
|
+
await importantOperation()
|
|
163
|
+
catch error:
|
|
164
|
+
// Nothing here - error lost!
|
|
165
|
+
|
|
166
|
+
// ✅ Good: Log at minimum
|
|
167
|
+
try:
|
|
168
|
+
await importantOperation()
|
|
169
|
+
catch error:
|
|
170
|
+
log("Operation failed:", error)
|
|
171
|
+
throw error // Or handle appropriately
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### Don't Use Errors for Flow Control
|
|
175
|
+
|
|
176
|
+
```pseudocode
|
|
177
|
+
// ❌ Bad: Using errors for normal logic
|
|
178
|
+
try:
|
|
179
|
+
user = findUser(id)
|
|
180
|
+
// ...
|
|
181
|
+
catch error:
|
|
182
|
+
// User not found - this is expected, not an error!
|
|
183
|
+
|
|
184
|
+
// ✅ Good: Return null for expected cases
|
|
185
|
+
user = findUser(id)
|
|
186
|
+
if user is null:
|
|
187
|
+
print("User not found")
|
|
188
|
+
return
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
### Don't Throw Non-Error Objects
|
|
192
|
+
|
|
193
|
+
```pseudocode
|
|
194
|
+
// ❌ Bad
|
|
195
|
+
throw "Something went wrong" // String
|
|
196
|
+
throw { code: 500 } // Plain object
|
|
197
|
+
|
|
198
|
+
// ✅ Good
|
|
199
|
+
throw Error("Something went wrong")
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
## Best Practices
|
|
203
|
+
|
|
204
|
+
1. **Fail fast** - Validate input early and throw immediately
|
|
205
|
+
2. **Be specific** - Provide detailed, actionable error messages
|
|
206
|
+
3. **Log errors** - Always log for debugging
|
|
207
|
+
4. **Don't hide errors** - Let them propagate if you can't handle them
|
|
208
|
+
5. **Clean up resources** - Close connections, files in finally blocks
|
|
209
|
+
|
|
210
|
+
```pseudocode
|
|
211
|
+
file = null
|
|
212
|
+
try:
|
|
213
|
+
file = await openFile("data.txt")
|
|
214
|
+
await processFile(file)
|
|
215
|
+
catch error:
|
|
216
|
+
log("File processing failed:", error)
|
|
217
|
+
throw error
|
|
218
|
+
finally:
|
|
219
|
+
// Always runs, even if error thrown
|
|
220
|
+
if file is not null:
|
|
221
|
+
await file.close()
|
|
222
|
+
```
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
# Error Handling Strategy
|
|
2
|
+
|
|
3
|
+
## Custom Error Classes
|
|
4
|
+
|
|
5
|
+
```typescript
|
|
6
|
+
class AppError extends Error {
|
|
7
|
+
constructor(
|
|
8
|
+
message: string,
|
|
9
|
+
public statusCode: number = 500,
|
|
10
|
+
public code: string = 'INTERNAL_ERROR',
|
|
11
|
+
public details?: unknown
|
|
12
|
+
) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.name = this.constructor.name;
|
|
15
|
+
Error.captureStackTrace(this, this.constructor);
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
class NotFoundError extends AppError {
|
|
20
|
+
constructor(resource: string, id: string) {
|
|
21
|
+
super(`${resource} with id ${id} not found`, 404, 'NOT_FOUND', { resource, id });
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
class ValidationError extends AppError {
|
|
26
|
+
constructor(message: string, details: unknown) {
|
|
27
|
+
super(message, 400, 'VALIDATION_ERROR', details);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Usage
|
|
32
|
+
if (!user) {
|
|
33
|
+
throw new NotFoundError('User', userId);
|
|
34
|
+
}
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Never Swallow Errors
|
|
38
|
+
|
|
39
|
+
```typescript
|
|
40
|
+
// ❌ Silent failure - dangerous!
|
|
41
|
+
try {
|
|
42
|
+
await criticalOperation();
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// Error ignored
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// ✅ Log and handle appropriately
|
|
48
|
+
try {
|
|
49
|
+
await criticalOperation();
|
|
50
|
+
} catch (error) {
|
|
51
|
+
logger.error('Critical operation failed', { error });
|
|
52
|
+
throw error; // Or handle gracefully
|
|
53
|
+
}
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Specific Error Messages
|
|
57
|
+
|
|
58
|
+
```typescript
|
|
59
|
+
// ❌ Not actionable
|
|
60
|
+
throw new Error('Something went wrong');
|
|
61
|
+
|
|
62
|
+
// ✅ Specific and actionable
|
|
63
|
+
throw new ValidationError('Email must be a valid email address', {
|
|
64
|
+
field: 'email',
|
|
65
|
+
value: userInput.email
|
|
66
|
+
});
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
## Centralized Error Handler
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Express error middleware
|
|
73
|
+
app.use((err: Error, req: Request, res: Response, next: NextFunction) => {
|
|
74
|
+
if (err instanceof AppError) {
|
|
75
|
+
return res.status(err.statusCode).json({
|
|
76
|
+
error: {
|
|
77
|
+
message: err.message,
|
|
78
|
+
code: err.code,
|
|
79
|
+
details: err.details
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
// Log unexpected errors
|
|
85
|
+
console.error('Unexpected error:', err);
|
|
86
|
+
|
|
87
|
+
// Don't expose internal details
|
|
88
|
+
res.status(500).json({
|
|
89
|
+
error: {
|
|
90
|
+
message: 'Internal server error',
|
|
91
|
+
code: 'INTERNAL_ERROR'
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
});
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Async Error Wrapper
|
|
98
|
+
|
|
99
|
+
```typescript
|
|
100
|
+
// Wrap async handlers to catch errors automatically
|
|
101
|
+
const asyncHandler = (fn: RequestHandler) => {
|
|
102
|
+
return (req: Request, res: Response, next: NextFunction) => {
|
|
103
|
+
Promise.resolve(fn(req, res, next)).catch(next);
|
|
104
|
+
};
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
// Usage
|
|
108
|
+
app.get('/users/:id', asyncHandler(async (req, res) => {
|
|
109
|
+
const user = await getUser(req.params.id);
|
|
110
|
+
res.json(user);
|
|
111
|
+
}));
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
## Result Type Pattern
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
type Result<T, E = Error> =
|
|
118
|
+
| { success: true; value: T }
|
|
119
|
+
| { success: false; error: E };
|
|
120
|
+
|
|
121
|
+
function parseJSON<T>(json: string): Result<T, string> {
|
|
122
|
+
try {
|
|
123
|
+
return { success: true, value: JSON.parse(json) };
|
|
124
|
+
} catch {
|
|
125
|
+
return { success: false, error: 'Invalid JSON' };
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// Usage - forces explicit error handling
|
|
130
|
+
const result = parseJSON<User>(data);
|
|
131
|
+
if (result.success) {
|
|
132
|
+
console.log(result.value.name);
|
|
133
|
+
} else {
|
|
134
|
+
console.error(result.error);
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
## Error Boundaries (React)
|
|
139
|
+
|
|
140
|
+
```typescript
|
|
141
|
+
class ErrorBoundary extends React.Component {
|
|
142
|
+
state = { hasError: false };
|
|
143
|
+
|
|
144
|
+
static getDerivedStateFromError(error: Error) {
|
|
145
|
+
return { hasError: true };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
|
|
149
|
+
logger.error('UI Error', { error, errorInfo });
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
render() {
|
|
153
|
+
if (this.state.hasError) {
|
|
154
|
+
return <FallbackUI />;
|
|
155
|
+
}
|
|
156
|
+
return this.props.children;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
## Retry with Limits
|
|
162
|
+
|
|
163
|
+
```typescript
|
|
164
|
+
// ❌ Infinite retries
|
|
165
|
+
while (true) {
|
|
166
|
+
try {
|
|
167
|
+
await operation();
|
|
168
|
+
break;
|
|
169
|
+
} catch (error) {
|
|
170
|
+
// Retry forever - exhausts resources
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// ✅ Limited retries with backoff
|
|
175
|
+
const maxRetries = 3;
|
|
176
|
+
for (let i = 0; i < maxRetries; i++) {
|
|
177
|
+
try {
|
|
178
|
+
await operation();
|
|
179
|
+
break;
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (i === maxRetries - 1) throw error;
|
|
182
|
+
await sleep(Math.pow(2, i) * 1000); // Exponential backoff
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
```
|