thevoidforge 21.0.11 → 21.0.13
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/dist/.claude/commands/ai.md +69 -0
- package/dist/.claude/commands/architect.md +121 -0
- package/dist/.claude/commands/assemble.md +201 -0
- package/dist/.claude/commands/assess.md +75 -0
- package/dist/.claude/commands/blueprint.md +135 -0
- package/dist/.claude/commands/build.md +116 -0
- package/dist/.claude/commands/campaign.md +201 -0
- package/dist/.claude/commands/cultivation.md +166 -0
- package/dist/.claude/commands/current.md +128 -0
- package/dist/.claude/commands/dangerroom.md +74 -0
- package/dist/.claude/commands/debrief.md +178 -0
- package/dist/.claude/commands/deploy.md +99 -0
- package/dist/.claude/commands/devops.md +143 -0
- package/dist/.claude/commands/gauntlet.md +140 -0
- package/dist/.claude/commands/git.md +104 -0
- package/dist/.claude/commands/grow.md +146 -0
- package/dist/.claude/commands/imagine.md +126 -0
- package/dist/.claude/commands/portfolio.md +50 -0
- package/dist/.claude/commands/prd.md +113 -0
- package/dist/.claude/commands/qa.md +107 -0
- package/dist/.claude/commands/review.md +151 -0
- package/dist/.claude/commands/security.md +100 -0
- package/dist/.claude/commands/test.md +96 -0
- package/dist/.claude/commands/thumper.md +116 -0
- package/dist/.claude/commands/treasury.md +100 -0
- package/dist/.claude/commands/ux.md +118 -0
- package/dist/.claude/commands/vault.md +189 -0
- package/dist/.claude/commands/void.md +108 -0
- package/dist/CHANGELOG.md +1918 -0
- package/dist/CLAUDE.md +250 -0
- package/dist/HOLOCRON.md +856 -0
- package/dist/VERSION.md +123 -0
- package/dist/docs/NAMING_REGISTRY.md +478 -0
- package/dist/docs/methods/AI_INTELLIGENCE.md +276 -0
- package/dist/docs/methods/ASSEMBLER.md +142 -0
- package/dist/docs/methods/BACKEND_ENGINEER.md +165 -0
- package/dist/docs/methods/BUILD_JOURNAL.md +185 -0
- package/dist/docs/methods/BUILD_PROTOCOL.md +426 -0
- package/dist/docs/methods/CAMPAIGN.md +568 -0
- package/dist/docs/methods/CONTEXT_MANAGEMENT.md +189 -0
- package/dist/docs/methods/DEEP_CURRENT.md +184 -0
- package/dist/docs/methods/DEVOPS_ENGINEER.md +295 -0
- package/dist/docs/methods/FIELD_MEDIC.md +261 -0
- package/dist/docs/methods/FORGE_ARTIST.md +108 -0
- package/dist/docs/methods/FORGE_KEEPER.md +268 -0
- package/dist/docs/methods/GAUNTLET.md +344 -0
- package/dist/docs/methods/GROWTH_STRATEGIST.md +466 -0
- package/dist/docs/methods/HEARTBEAT.md +168 -0
- package/dist/docs/methods/MCP_INTEGRATION.md +139 -0
- package/dist/docs/methods/MUSTER.md +148 -0
- package/dist/docs/methods/PRD_GENERATOR.md +186 -0
- package/dist/docs/methods/PRODUCT_DESIGN_FRONTEND.md +250 -0
- package/dist/docs/methods/QA_ENGINEER.md +337 -0
- package/dist/docs/methods/RELEASE_MANAGER.md +145 -0
- package/dist/docs/methods/SECURITY_AUDITOR.md +320 -0
- package/dist/docs/methods/SUB_AGENTS.md +335 -0
- package/dist/docs/methods/SYSTEMS_ARCHITECT.md +171 -0
- package/dist/docs/methods/TESTING.md +359 -0
- package/dist/docs/methods/THUMPER.md +175 -0
- package/dist/docs/methods/TIME_VAULT.md +120 -0
- package/dist/docs/methods/TREASURY.md +184 -0
- package/dist/docs/methods/TROUBLESHOOTING.md +265 -0
- package/dist/docs/patterns/README.md +52 -0
- package/dist/docs/patterns/ad-billing-adapter.ts +537 -0
- package/dist/docs/patterns/ad-platform-adapter.ts +421 -0
- package/dist/docs/patterns/ai-classifier.ts +195 -0
- package/dist/docs/patterns/ai-eval.ts +272 -0
- package/dist/docs/patterns/ai-orchestrator.ts +341 -0
- package/dist/docs/patterns/ai-router.ts +194 -0
- package/dist/docs/patterns/ai-tool-schema.ts +237 -0
- package/dist/docs/patterns/api-route.ts +241 -0
- package/dist/docs/patterns/backtest-engine.ts +499 -0
- package/dist/docs/patterns/browser-review.ts +292 -0
- package/dist/docs/patterns/combobox.tsx +300 -0
- package/dist/docs/patterns/component.tsx +262 -0
- package/dist/docs/patterns/daemon-process.ts +338 -0
- package/dist/docs/patterns/data-pipeline.ts +297 -0
- package/dist/docs/patterns/database-migration.ts +466 -0
- package/dist/docs/patterns/e2e-test.ts +629 -0
- package/dist/docs/patterns/error-handling.ts +312 -0
- package/dist/docs/patterns/execution-safety.ts +601 -0
- package/dist/docs/patterns/financial-transaction.ts +342 -0
- package/dist/docs/patterns/funding-plan.ts +462 -0
- package/dist/docs/patterns/game-entity.ts +137 -0
- package/dist/docs/patterns/game-loop.ts +113 -0
- package/dist/docs/patterns/game-state.ts +143 -0
- package/dist/docs/patterns/job-queue.ts +225 -0
- package/dist/docs/patterns/kongo-integration.ts +164 -0
- package/dist/docs/patterns/middleware.ts +363 -0
- package/dist/docs/patterns/mobile-screen.tsx +139 -0
- package/dist/docs/patterns/mobile-service.ts +167 -0
- package/dist/docs/patterns/multi-tenant.ts +382 -0
- package/dist/docs/patterns/oauth-token-lifecycle.ts +223 -0
- package/dist/docs/patterns/outbound-rate-limiter.ts +260 -0
- package/dist/docs/patterns/prompt-template.ts +195 -0
- package/dist/docs/patterns/revenue-source-adapter.ts +311 -0
- package/dist/docs/patterns/service.ts +224 -0
- package/dist/docs/patterns/sse-endpoint.ts +118 -0
- package/dist/docs/patterns/stablecoin-adapter.ts +511 -0
- package/dist/docs/patterns/third-party-script.ts +68 -0
- package/dist/scripts/thumper/gom-jabbar.sh +241 -0
- package/dist/scripts/thumper/relay.sh +610 -0
- package/dist/scripts/thumper/scan.sh +359 -0
- package/dist/scripts/thumper/thumper.sh +190 -0
- package/dist/scripts/thumper/water-rings.sh +76 -0
- package/dist/wizard/ui/index.html +1 -1
- package/package.json +1 -1
- package/dist/tsconfig.tsbuildinfo +0 -1
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern: Error Handling Strategy (Canonical Reference)
|
|
3
|
+
*
|
|
4
|
+
* This is the single source of truth for error handling across VoidForge.
|
|
5
|
+
* All other patterns (api-route.ts, service.ts, middleware.ts) reference this.
|
|
6
|
+
*
|
|
7
|
+
* Key principles:
|
|
8
|
+
* - Custom error types with codes, not raw Error throws
|
|
9
|
+
* - Catch at boundaries (route handlers), not in services
|
|
10
|
+
* - Never leak internals (stack traces, DB errors, file paths)
|
|
11
|
+
* - Structured error responses with consistent shape
|
|
12
|
+
* - Log errors with context (requestId, userId, action)
|
|
13
|
+
* - Different handling for operational vs programmer errors
|
|
14
|
+
*
|
|
15
|
+
* Agents: Barton (error handling), Kenobi (security — never leak), L (monitoring)
|
|
16
|
+
*
|
|
17
|
+
* Framework adaptations:
|
|
18
|
+
* Next.js: Global error handler in middleware or route wrapper
|
|
19
|
+
* Django: Custom exception handler in DRF, or middleware
|
|
20
|
+
* Rails: rescue_from in ApplicationController
|
|
21
|
+
* Express: Error-handling middleware (err, req, res, next)
|
|
22
|
+
*
|
|
23
|
+
* === Django Deep Dive (DRF) ===
|
|
24
|
+
*
|
|
25
|
+
* # app/exceptions.py — domain exceptions (same shape as TypeScript ApiError)
|
|
26
|
+
* class AppError(Exception):
|
|
27
|
+
* def __init__(self, message, status_code=500, code="INTERNAL_ERROR"):
|
|
28
|
+
* self.message = message
|
|
29
|
+
* self.status_code = status_code
|
|
30
|
+
* self.code = code
|
|
31
|
+
*
|
|
32
|
+
* class NotFoundError(AppError):
|
|
33
|
+
* def __init__(self, message="Not found"):
|
|
34
|
+
* super().__init__(message, 404, "NOT_FOUND")
|
|
35
|
+
*
|
|
36
|
+
* class ForbiddenError(AppError):
|
|
37
|
+
* def __init__(self, message="Forbidden"):
|
|
38
|
+
* super().__init__(message, 403, "FORBIDDEN")
|
|
39
|
+
*
|
|
40
|
+
* class ValidationError(AppError):
|
|
41
|
+
* def __init__(self, message="Validation failed"):
|
|
42
|
+
* super().__init__(message, 400, "VALIDATION_ERROR")
|
|
43
|
+
*
|
|
44
|
+
* # settings.py — register custom handler
|
|
45
|
+
* REST_FRAMEWORK = {
|
|
46
|
+
* 'EXCEPTION_HANDLER': 'app.exception_handler.custom_exception_handler'
|
|
47
|
+
* }
|
|
48
|
+
*
|
|
49
|
+
* # app/exception_handler.py
|
|
50
|
+
* def custom_exception_handler(exc, context):
|
|
51
|
+
* if isinstance(exc, AppError):
|
|
52
|
+
* return Response(
|
|
53
|
+
* {"success": False, "error": exc.message, "code": exc.code},
|
|
54
|
+
* status=exc.status_code
|
|
55
|
+
* )
|
|
56
|
+
* # Fall through to DRF default for validation errors, auth errors, etc.
|
|
57
|
+
* response = exception_handler(exc, context)
|
|
58
|
+
* if response: return response
|
|
59
|
+
* # Unhandled — log and return 500 (never leak internals)
|
|
60
|
+
* logger.error(f"Unhandled: {exc}", exc_info=True)
|
|
61
|
+
* return Response({"success": False, "error": "Internal error"}, status=500)
|
|
62
|
+
*
|
|
63
|
+
* === FastAPI Deep Dive ===
|
|
64
|
+
*
|
|
65
|
+
* # app/exceptions.py — same domain exceptions
|
|
66
|
+
* class AppError(Exception):
|
|
67
|
+
* def __init__(self, message: str, status_code: int = 500, code: str = "INTERNAL_ERROR"):
|
|
68
|
+
* self.message = message
|
|
69
|
+
* self.status_code = status_code
|
|
70
|
+
* self.code = code
|
|
71
|
+
*
|
|
72
|
+
* # app/main.py — register handler
|
|
73
|
+
* @app.exception_handler(AppError)
|
|
74
|
+
* async def app_error_handler(request, exc: AppError):
|
|
75
|
+
* return JSONResponse(
|
|
76
|
+
* status_code=exc.status_code,
|
|
77
|
+
* content={"success": False, "error": exc.message, "code": exc.code}
|
|
78
|
+
* )
|
|
79
|
+
*
|
|
80
|
+
* @app.exception_handler(Exception)
|
|
81
|
+
* async def unhandled_error_handler(request, exc):
|
|
82
|
+
* logger.error(f"Unhandled: {exc}", exc_info=True)
|
|
83
|
+
* return JSONResponse(
|
|
84
|
+
* status_code=500,
|
|
85
|
+
* content={"success": False, "error": "Internal error"}
|
|
86
|
+
* )
|
|
87
|
+
*
|
|
88
|
+
* # Pydantic validation errors are handled automatically by FastAPI (422)
|
|
89
|
+
* # Never leak stack traces — the unhandled handler catches everything
|
|
90
|
+
*/
|
|
91
|
+
|
|
92
|
+
// ============================================================
|
|
93
|
+
// 1. ERROR TYPES — used across all services
|
|
94
|
+
// ============================================================
|
|
95
|
+
|
|
96
|
+
export class ApiError extends Error {
|
|
97
|
+
constructor(
|
|
98
|
+
public code: string,
|
|
99
|
+
message: string,
|
|
100
|
+
public status: number
|
|
101
|
+
) {
|
|
102
|
+
super(message)
|
|
103
|
+
this.name = 'ApiError'
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Pre-built errors for common cases
|
|
108
|
+
export const Errors = {
|
|
109
|
+
unauthorized: () => new ApiError('UNAUTHORIZED', 'Authentication required', 401),
|
|
110
|
+
forbidden: () => new ApiError('FORBIDDEN', 'Insufficient permissions', 403),
|
|
111
|
+
notFound: (resource = 'Resource') => new ApiError('NOT_FOUND', `${resource} not found`, 404),
|
|
112
|
+
validation: (details: Record<string, string[]>) =>
|
|
113
|
+
Object.assign(new ApiError('VALIDATION_ERROR', 'Invalid input', 400), { details }),
|
|
114
|
+
conflict: (message: string) => new ApiError('CONFLICT', message, 409),
|
|
115
|
+
rateLimited: () => new ApiError('RATE_LIMITED', 'Too many requests', 429),
|
|
116
|
+
internal: () => new ApiError('INTERNAL_ERROR', 'Something went wrong', 500),
|
|
117
|
+
} as const
|
|
118
|
+
|
|
119
|
+
// ============================================================
|
|
120
|
+
// 2. ERROR RESPONSE SHAPE — consistent across all routes
|
|
121
|
+
// ============================================================
|
|
122
|
+
|
|
123
|
+
/*
|
|
124
|
+
Success:
|
|
125
|
+
{
|
|
126
|
+
"data": { ... }
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
Error:
|
|
130
|
+
{
|
|
131
|
+
"error": {
|
|
132
|
+
"code": "VALIDATION_ERROR", // Machine-readable
|
|
133
|
+
"message": "Invalid input", // Human-readable
|
|
134
|
+
"details": { ... } // Optional — field-level errors
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
Never include:
|
|
139
|
+
- Stack traces
|
|
140
|
+
- Internal file paths
|
|
141
|
+
- Database error messages
|
|
142
|
+
- SQL queries
|
|
143
|
+
- Environment variable names
|
|
144
|
+
*/
|
|
145
|
+
|
|
146
|
+
// ============================================================
|
|
147
|
+
// 3. GLOBAL ERROR HANDLER — catches everything at the boundary
|
|
148
|
+
// ============================================================
|
|
149
|
+
|
|
150
|
+
import { NextResponse } from 'next/server'
|
|
151
|
+
|
|
152
|
+
export function handleApiError(error: unknown): NextResponse {
|
|
153
|
+
// Known operational errors — safe to expose
|
|
154
|
+
if (error instanceof ApiError) {
|
|
155
|
+
const body: Record<string, unknown> = {
|
|
156
|
+
error: {
|
|
157
|
+
code: error.code,
|
|
158
|
+
message: error.message,
|
|
159
|
+
},
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Include validation details if present
|
|
163
|
+
if ('details' in error) {
|
|
164
|
+
(body.error as Record<string, unknown>).details = (error as any).details
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
return NextResponse.json(body, { status: error.status })
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Unknown/programmer errors — log everything, expose nothing
|
|
171
|
+
const errorMessage = error instanceof Error ? error.message : 'Unknown error'
|
|
172
|
+
const errorStack = error instanceof Error ? error.stack : undefined
|
|
173
|
+
|
|
174
|
+
// Structured log with full context (L — monitoring)
|
|
175
|
+
console.error(JSON.stringify({
|
|
176
|
+
event: 'unhandled_error',
|
|
177
|
+
message: errorMessage,
|
|
178
|
+
stack: errorStack,
|
|
179
|
+
timestamp: new Date().toISOString(),
|
|
180
|
+
// requestId and userId would be added by logging middleware
|
|
181
|
+
}))
|
|
182
|
+
|
|
183
|
+
// Generic response — never leak internals (Kenobi)
|
|
184
|
+
return NextResponse.json(
|
|
185
|
+
{ error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' } },
|
|
186
|
+
{ status: 500 }
|
|
187
|
+
)
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// ============================================================
|
|
191
|
+
// 4. USAGE IN SERVICES — throw typed errors
|
|
192
|
+
// ============================================================
|
|
193
|
+
|
|
194
|
+
/*
|
|
195
|
+
// In a service:
|
|
196
|
+
async function getProject(id: string, userId: string) {
|
|
197
|
+
const project = await db.project.findUnique({ where: { id } })
|
|
198
|
+
|
|
199
|
+
if (!project) {
|
|
200
|
+
throw Errors.notFound('Project') // 404 — clear, typed
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
if (project.ownerId !== userId) {
|
|
204
|
+
throw Errors.notFound('Project') // 404 (not 403) — don't reveal existence
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
return project
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// In a route handler:
|
|
211
|
+
export async function GET(req: NextRequest) {
|
|
212
|
+
try {
|
|
213
|
+
const project = await getProject(id, userId)
|
|
214
|
+
return NextResponse.json({ data: project })
|
|
215
|
+
} catch (error) {
|
|
216
|
+
return handleApiError(error) // Single catch, handles everything
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
*/
|
|
220
|
+
|
|
221
|
+
// ============================================================
|
|
222
|
+
// 5. OPERATIONAL vs PROGRAMMER ERRORS
|
|
223
|
+
// ============================================================
|
|
224
|
+
|
|
225
|
+
/*
|
|
226
|
+
OPERATIONAL (expected, handled):
|
|
227
|
+
- User not found → 404
|
|
228
|
+
- Invalid input → 400
|
|
229
|
+
- Unauthorized → 401
|
|
230
|
+
- Rate limited → 429
|
|
231
|
+
- External API down → 503 (with retry header)
|
|
232
|
+
→ Throw ApiError. The handler returns the right status code.
|
|
233
|
+
|
|
234
|
+
PROGRAMMER (unexpected, bugs):
|
|
235
|
+
- TypeError, ReferenceError
|
|
236
|
+
- Unhandled promise rejection
|
|
237
|
+
- Database connection lost
|
|
238
|
+
- Out of memory
|
|
239
|
+
→ Caught by handleApiError's fallback. Returns 500. Logged with full stack.
|
|
240
|
+
These indicate bugs — investigate and fix the root cause.
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
// ============================================================
|
|
244
|
+
// 6. FRAMEWORK ADAPTATIONS
|
|
245
|
+
// ============================================================
|
|
246
|
+
|
|
247
|
+
// --- Express error middleware ---
|
|
248
|
+
/*
|
|
249
|
+
// middleware/errorHandler.ts
|
|
250
|
+
import { Request, Response, NextFunction } from 'express'
|
|
251
|
+
|
|
252
|
+
export function errorHandler(err: unknown, req: Request, res: Response, next: NextFunction) {
|
|
253
|
+
if (err instanceof ApiError) {
|
|
254
|
+
return res.status(err.status).json({
|
|
255
|
+
error: { code: err.code, message: err.message }
|
|
256
|
+
})
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
console.error(JSON.stringify({
|
|
260
|
+
event: 'unhandled_error',
|
|
261
|
+
message: err instanceof Error ? err.message : 'Unknown',
|
|
262
|
+
path: req.path,
|
|
263
|
+
method: req.method,
|
|
264
|
+
}))
|
|
265
|
+
|
|
266
|
+
res.status(500).json({
|
|
267
|
+
error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' }
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// app.ts — register LAST
|
|
272
|
+
app.use(errorHandler)
|
|
273
|
+
*/
|
|
274
|
+
|
|
275
|
+
// --- Django exception handler ---
|
|
276
|
+
/*
|
|
277
|
+
# utils/exceptions.py
|
|
278
|
+
from rest_framework.views import exception_handler
|
|
279
|
+
from rest_framework.response import Response
|
|
280
|
+
|
|
281
|
+
def custom_exception_handler(exc, context):
|
|
282
|
+
if isinstance(exc, ApiError):
|
|
283
|
+
return Response(
|
|
284
|
+
{'error': {'code': exc.code, 'message': str(exc)}},
|
|
285
|
+
status=exc.status_code
|
|
286
|
+
)
|
|
287
|
+
|
|
288
|
+
response = exception_handler(exc, context)
|
|
289
|
+
if response is None:
|
|
290
|
+
logger.error(f'Unhandled error: {exc}', exc_info=True)
|
|
291
|
+
return Response(
|
|
292
|
+
{'error': {'code': 'INTERNAL_ERROR', 'message': 'Something went wrong'}},
|
|
293
|
+
status=500
|
|
294
|
+
)
|
|
295
|
+
return response
|
|
296
|
+
*/
|
|
297
|
+
|
|
298
|
+
// --- Rails rescue_from ---
|
|
299
|
+
/*
|
|
300
|
+
# app/controllers/application_controller.rb
|
|
301
|
+
class ApplicationController < ActionController::API
|
|
302
|
+
rescue_from ApiError do |e|
|
|
303
|
+
render json: { error: { code: e.code, message: e.message } }, status: e.status
|
|
304
|
+
end
|
|
305
|
+
|
|
306
|
+
rescue_from StandardError do |e|
|
|
307
|
+
Rails.logger.error("Unhandled error: #{e.message}\n#{e.backtrace.first(5).join("\n")}")
|
|
308
|
+
render json: { error: { code: 'INTERNAL_ERROR', message: 'Something went wrong' } },
|
|
309
|
+
status: :internal_server_error
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
*/
|