honertia 0.1.21 → 0.1.22
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/README.md +111 -4
- package/dist/effect/binding.d.ts.map +1 -1
- package/dist/effect/binding.js +1 -4
- package/dist/effect/bridge.d.ts.map +1 -1
- package/dist/effect/bridge.js +11 -3
- package/dist/effect/error-catalog.d.ts +100 -0
- package/dist/effect/error-catalog.d.ts.map +1 -0
- package/dist/effect/error-catalog.js +700 -0
- package/dist/effect/error-context.d.ts +99 -0
- package/dist/effect/error-context.d.ts.map +1 -0
- package/dist/effect/error-context.js +230 -0
- package/dist/effect/error-formatter.d.ts +143 -0
- package/dist/effect/error-formatter.d.ts.map +1 -0
- package/dist/effect/error-formatter.js +355 -0
- package/dist/effect/error-types.d.ts +275 -0
- package/dist/effect/error-types.d.ts.map +1 -0
- package/dist/effect/error-types.js +7 -0
- package/dist/effect/errors.d.ts +183 -15
- package/dist/effect/errors.d.ts.map +1 -1
- package/dist/effect/errors.js +333 -8
- package/dist/effect/handler.d.ts +6 -0
- package/dist/effect/handler.d.ts.map +1 -1
- package/dist/effect/handler.js +124 -12
- package/dist/effect/index.d.ts +7 -3
- package/dist/effect/index.d.ts.map +1 -1
- package/dist/effect/index.js +9 -3
- package/dist/effect/validation.d.ts +16 -0
- package/dist/effect/validation.d.ts.map +1 -1
- package/dist/effect/validation.js +70 -4
- package/dist/helpers.d.ts.map +1 -1
- package/dist/helpers.js +5 -1
- package/dist/setup.d.ts.map +1 -1
- package/dist/setup.js +77 -12
- package/package.json +1 -1
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error Formatters for Honertia
|
|
3
|
+
*
|
|
4
|
+
* Multiple output formats for structured errors:
|
|
5
|
+
* - JSON for AI/API consumption
|
|
6
|
+
* - Terminal with ANSI colors for CLI
|
|
7
|
+
* - Inertia for browser rendering
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* JSON formatter for AI/LLM and API consumption.
|
|
11
|
+
* Outputs machine-readable structured error data.
|
|
12
|
+
*/
|
|
13
|
+
export class JsonErrorFormatter {
|
|
14
|
+
options;
|
|
15
|
+
constructor(options = {}) {
|
|
16
|
+
this.options = options;
|
|
17
|
+
// Default all options to true
|
|
18
|
+
this.options = {
|
|
19
|
+
pretty: true,
|
|
20
|
+
includeSource: true,
|
|
21
|
+
includeContext: true,
|
|
22
|
+
includeFixes: true,
|
|
23
|
+
includeDocs: true,
|
|
24
|
+
...options,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
format(error) {
|
|
28
|
+
// Cast to allow accessing extended properties
|
|
29
|
+
const errorObj = error;
|
|
30
|
+
const output = {
|
|
31
|
+
code: error.code,
|
|
32
|
+
tag: error.tag,
|
|
33
|
+
category: error.category,
|
|
34
|
+
title: error.title,
|
|
35
|
+
message: error.message,
|
|
36
|
+
httpStatus: error.httpStatus,
|
|
37
|
+
timestamp: error.timestamp,
|
|
38
|
+
};
|
|
39
|
+
if (error.requestId) {
|
|
40
|
+
output.requestId = error.requestId;
|
|
41
|
+
}
|
|
42
|
+
if (this.options.includeSource && error.source) {
|
|
43
|
+
output.source = error.source;
|
|
44
|
+
}
|
|
45
|
+
if (this.options.includeContext && error.context) {
|
|
46
|
+
output.context = error.context;
|
|
47
|
+
}
|
|
48
|
+
if (this.options.includeFixes && error.fixes.length > 0) {
|
|
49
|
+
output.fixes = error.fixes;
|
|
50
|
+
}
|
|
51
|
+
// Include extended properties (validation, configuration, binding, etc.)
|
|
52
|
+
const baseKeys = new Set([
|
|
53
|
+
'code', 'tag', 'category', 'title', 'message', 'httpStatus',
|
|
54
|
+
'timestamp', 'requestId', 'source', 'context', 'fixes', 'docs'
|
|
55
|
+
]);
|
|
56
|
+
for (const key of Object.keys(errorObj)) {
|
|
57
|
+
if (!baseKeys.has(key)) {
|
|
58
|
+
output[key] = errorObj[key];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
if (this.options.includeDocs && error.docs) {
|
|
62
|
+
output.docs = error.docs;
|
|
63
|
+
}
|
|
64
|
+
return output;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Format to JSON string.
|
|
68
|
+
*/
|
|
69
|
+
formatString(error) {
|
|
70
|
+
const obj = this.format(error);
|
|
71
|
+
return this.options.pretty ? JSON.stringify(obj, null, 2) : JSON.stringify(obj);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* ANSI color codes for terminal output.
|
|
76
|
+
*/
|
|
77
|
+
const colors = {
|
|
78
|
+
red: '\x1b[31m',
|
|
79
|
+
yellow: '\x1b[33m',
|
|
80
|
+
green: '\x1b[32m',
|
|
81
|
+
cyan: '\x1b[36m',
|
|
82
|
+
blue: '\x1b[34m',
|
|
83
|
+
magenta: '\x1b[35m',
|
|
84
|
+
gray: '\x1b[90m',
|
|
85
|
+
white: '\x1b[37m',
|
|
86
|
+
bold: '\x1b[1m',
|
|
87
|
+
dim: '\x1b[2m',
|
|
88
|
+
reset: '\x1b[0m',
|
|
89
|
+
underline: '\x1b[4m',
|
|
90
|
+
};
|
|
91
|
+
/**
|
|
92
|
+
* Terminal formatter with ANSI colors.
|
|
93
|
+
* Outputs Rust/Elm-style human-readable errors.
|
|
94
|
+
*/
|
|
95
|
+
export class TerminalErrorFormatter {
|
|
96
|
+
options;
|
|
97
|
+
c;
|
|
98
|
+
constructor(options = {}) {
|
|
99
|
+
this.options = options;
|
|
100
|
+
this.options = {
|
|
101
|
+
useColors: true,
|
|
102
|
+
showSnippet: true,
|
|
103
|
+
showFixes: true,
|
|
104
|
+
maxFixes: 3,
|
|
105
|
+
...options,
|
|
106
|
+
};
|
|
107
|
+
// Use colors or empty strings
|
|
108
|
+
this.c = this.options.useColors
|
|
109
|
+
? colors
|
|
110
|
+
: Object.fromEntries(Object.keys(colors).map((k) => [k, '']));
|
|
111
|
+
}
|
|
112
|
+
format(error) {
|
|
113
|
+
const { c } = this;
|
|
114
|
+
const lines = [];
|
|
115
|
+
// Empty line for spacing
|
|
116
|
+
lines.push('');
|
|
117
|
+
// Header with error code
|
|
118
|
+
lines.push(`${c.red}${c.bold}ERROR${c.reset} ${c.gray}[${error.code}]${c.reset}`);
|
|
119
|
+
lines.push(`${c.bold}${error.title}${c.reset}`);
|
|
120
|
+
lines.push('');
|
|
121
|
+
// Message
|
|
122
|
+
lines.push(error.message);
|
|
123
|
+
lines.push('');
|
|
124
|
+
// Source location with code snippet
|
|
125
|
+
if (error.source) {
|
|
126
|
+
lines.push(`${c.cyan}Location:${c.reset}`);
|
|
127
|
+
lines.push(` ${c.dim}${error.source.file}:${error.source.line}:${error.source.column}${c.reset}`);
|
|
128
|
+
if (this.options.showSnippet && error.source.codeSnippet) {
|
|
129
|
+
lines.push('');
|
|
130
|
+
const snippet = error.source.codeSnippet;
|
|
131
|
+
const errorLine = error.source.line;
|
|
132
|
+
const startLine = errorLine - snippet.before.length;
|
|
133
|
+
// Lines before
|
|
134
|
+
snippet.before.forEach((line, i) => {
|
|
135
|
+
const lineNum = String(startLine + i).padStart(4);
|
|
136
|
+
lines.push(`${c.gray}${lineNum} |${c.reset} ${line}`);
|
|
137
|
+
});
|
|
138
|
+
// Error line (highlighted)
|
|
139
|
+
const errorLineNum = String(errorLine).padStart(4);
|
|
140
|
+
lines.push(`${c.red}${errorLineNum} |${c.reset} ${snippet.line}`);
|
|
141
|
+
// Pointer arrow
|
|
142
|
+
if (snippet.highlight) {
|
|
143
|
+
const padding = ' '.repeat(7 + snippet.highlight.start);
|
|
144
|
+
const arrows = '^'.repeat(Math.max(1, snippet.highlight.end - snippet.highlight.start));
|
|
145
|
+
lines.push(`${c.red}${padding}${arrows}${c.reset}`);
|
|
146
|
+
}
|
|
147
|
+
// Lines after
|
|
148
|
+
snippet.after.forEach((line, i) => {
|
|
149
|
+
const lineNum = String(errorLine + 1 + i).padStart(4);
|
|
150
|
+
lines.push(`${c.gray}${lineNum} |${c.reset} ${line}`);
|
|
151
|
+
});
|
|
152
|
+
lines.push('');
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// Route context
|
|
156
|
+
if (error.context.route) {
|
|
157
|
+
const { method, path, params } = error.context.route;
|
|
158
|
+
lines.push(`${c.cyan}Route:${c.reset} ${method} ${path}`);
|
|
159
|
+
if (Object.keys(params).length > 0) {
|
|
160
|
+
lines.push(`${c.cyan}Params:${c.reset} ${JSON.stringify(params)}`);
|
|
161
|
+
}
|
|
162
|
+
lines.push('');
|
|
163
|
+
}
|
|
164
|
+
// Fix suggestions
|
|
165
|
+
if (this.options.showFixes && error.fixes.length > 0) {
|
|
166
|
+
lines.push(`${c.yellow}${c.bold}Suggested Fixes:${c.reset}`);
|
|
167
|
+
const fixesToShow = error.fixes.slice(0, this.options.maxFixes);
|
|
168
|
+
fixesToShow.forEach((fix, i) => {
|
|
169
|
+
const confidence = fix.confidence === 'high'
|
|
170
|
+
? `${c.green}[high]${c.reset}`
|
|
171
|
+
: fix.confidence === 'medium'
|
|
172
|
+
? `${c.yellow}[med]${c.reset}`
|
|
173
|
+
: `${c.gray}[low]${c.reset}`;
|
|
174
|
+
const auto = fix.automated ? `${c.cyan}(auto)${c.reset} ` : '';
|
|
175
|
+
lines.push(` ${i + 1}. ${confidence} ${auto}${fix.description}`);
|
|
176
|
+
// Show code preview if available
|
|
177
|
+
if (fix.operations[0]?.content) {
|
|
178
|
+
const preview = fix.operations[0].content.trim().split('\n')[0];
|
|
179
|
+
if (preview.length > 60) {
|
|
180
|
+
lines.push(` ${c.dim}${preview.slice(0, 60)}...${c.reset}`);
|
|
181
|
+
}
|
|
182
|
+
else {
|
|
183
|
+
lines.push(` ${c.dim}${preview}${c.reset}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
if (error.fixes.length > (this.options.maxFixes ?? 3)) {
|
|
188
|
+
lines.push(` ${c.dim}... and ${error.fixes.length - (this.options.maxFixes ?? 3)} more${c.reset}`);
|
|
189
|
+
}
|
|
190
|
+
lines.push('');
|
|
191
|
+
}
|
|
192
|
+
// Documentation link
|
|
193
|
+
if (error.docs?.url) {
|
|
194
|
+
lines.push(`${c.cyan}Docs:${c.reset} ${c.underline}${error.docs.url}${c.reset}`);
|
|
195
|
+
lines.push('');
|
|
196
|
+
}
|
|
197
|
+
return lines.join('\n');
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Inertia formatter for browser error pages.
|
|
202
|
+
* Outputs props for an Inertia error component.
|
|
203
|
+
*/
|
|
204
|
+
export class InertiaErrorFormatter {
|
|
205
|
+
options;
|
|
206
|
+
constructor(options = {}) {
|
|
207
|
+
this.options = options;
|
|
208
|
+
this.options = {
|
|
209
|
+
includeFixes: true,
|
|
210
|
+
includeSource: true,
|
|
211
|
+
isDev: true,
|
|
212
|
+
...options,
|
|
213
|
+
};
|
|
214
|
+
}
|
|
215
|
+
format(error) {
|
|
216
|
+
const props = {
|
|
217
|
+
status: error.httpStatus,
|
|
218
|
+
code: error.code,
|
|
219
|
+
title: error.title,
|
|
220
|
+
message: this.options.isDev ? error.message : this.getSafeMessage(error),
|
|
221
|
+
};
|
|
222
|
+
if (this.options.includeFixes && error.fixes.length > 0) {
|
|
223
|
+
props.fixes = error.fixes.map((f) => ({
|
|
224
|
+
description: f.description,
|
|
225
|
+
confidence: f.confidence,
|
|
226
|
+
automated: f.automated,
|
|
227
|
+
}));
|
|
228
|
+
// Include first high-confidence fix as a hint
|
|
229
|
+
const highConfidenceFix = error.fixes.find((f) => f.confidence === 'high');
|
|
230
|
+
if (highConfidenceFix) {
|
|
231
|
+
props.hint = highConfidenceFix.description;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
if (this.options.includeSource && this.options.isDev && error.source) {
|
|
235
|
+
props.source = {
|
|
236
|
+
file: error.source.file,
|
|
237
|
+
line: error.source.line,
|
|
238
|
+
column: error.source.column,
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
if (error.docs?.url) {
|
|
242
|
+
props.docsUrl = error.docs.url;
|
|
243
|
+
}
|
|
244
|
+
return props;
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get a safe message for production (no sensitive details).
|
|
248
|
+
*/
|
|
249
|
+
getSafeMessage(error) {
|
|
250
|
+
// Configuration and internal errors should show generic messages in production
|
|
251
|
+
if (error.category === 'configuration' ||
|
|
252
|
+
error.category === 'internal' ||
|
|
253
|
+
error.category === 'database') {
|
|
254
|
+
return 'An error occurred. Please try again later.';
|
|
255
|
+
}
|
|
256
|
+
return error.message;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Detect the appropriate output format based on request headers and environment.
|
|
261
|
+
*
|
|
262
|
+
* Detection priority:
|
|
263
|
+
* 1. AI/CLI User-Agents (claude-code, curl) → 'json'
|
|
264
|
+
* 2. Accept: application/json header → 'json'
|
|
265
|
+
* 3. X-Inertia: true header → 'inertia'
|
|
266
|
+
* 4. Content-Type: application/json → 'json'
|
|
267
|
+
* 5. Development environment → 'terminal'
|
|
268
|
+
* 6. Production browser requests → 'inertia'
|
|
269
|
+
*
|
|
270
|
+
* @param request - Request context with header accessor, method, and URL.
|
|
271
|
+
* @param env - Environment variables for detecting dev/prod mode.
|
|
272
|
+
* @returns The detected output format: 'json', 'terminal', or 'inertia'.
|
|
273
|
+
*
|
|
274
|
+
* @example
|
|
275
|
+
* ```ts
|
|
276
|
+
* const format = detectOutputFormat(
|
|
277
|
+
* { header: (n) => c.req.header(n), method: c.req.method, url: c.req.url },
|
|
278
|
+
* c.env
|
|
279
|
+
* )
|
|
280
|
+
* const formatter = createFormatter(format, isDev)
|
|
281
|
+
* ```
|
|
282
|
+
*/
|
|
283
|
+
export function detectOutputFormat(request, env = {}) {
|
|
284
|
+
// Check for AI/CLI User-Agent
|
|
285
|
+
const userAgent = request.header('User-Agent') ?? '';
|
|
286
|
+
if (userAgent.includes('claude-code') ||
|
|
287
|
+
userAgent.includes('claude') ||
|
|
288
|
+
userAgent.includes('anthropic') ||
|
|
289
|
+
userAgent.includes('CLI') ||
|
|
290
|
+
userAgent.includes('curl')) {
|
|
291
|
+
return 'json';
|
|
292
|
+
}
|
|
293
|
+
// Check Accept header
|
|
294
|
+
const accept = request.header('Accept') ?? '';
|
|
295
|
+
if (accept.includes('application/json')) {
|
|
296
|
+
return 'json';
|
|
297
|
+
}
|
|
298
|
+
// Check for Inertia request
|
|
299
|
+
if (request.header('X-Inertia') === 'true') {
|
|
300
|
+
return 'inertia';
|
|
301
|
+
}
|
|
302
|
+
// Check Content-Type for API requests
|
|
303
|
+
const contentType = request.header('Content-Type') ?? '';
|
|
304
|
+
if (contentType.includes('application/json')) {
|
|
305
|
+
return 'json';
|
|
306
|
+
}
|
|
307
|
+
// Development mode defaults to terminal-style logging
|
|
308
|
+
const isDev = env.ENVIRONMENT === 'development' ||
|
|
309
|
+
env.NODE_ENV === 'development' ||
|
|
310
|
+
env.CF_PAGES_BRANCH !== undefined; // Cloudflare Pages preview
|
|
311
|
+
if (isDev) {
|
|
312
|
+
return 'terminal';
|
|
313
|
+
}
|
|
314
|
+
// Production browser requests get Inertia format
|
|
315
|
+
return 'inertia';
|
|
316
|
+
}
|
|
317
|
+
/**
|
|
318
|
+
* Create a formatter instance for the given output format.
|
|
319
|
+
*
|
|
320
|
+
* @param format - The output format: 'json', 'terminal', or 'inertia'.
|
|
321
|
+
* @param isDev - Whether to include dev-only details (source, context). Defaults to true.
|
|
322
|
+
* @returns An ErrorFormatter instance configured for the format.
|
|
323
|
+
*
|
|
324
|
+
* @example
|
|
325
|
+
* ```ts
|
|
326
|
+
* const format = detectOutputFormat(request, env)
|
|
327
|
+
* const formatter = createFormatter(format, isDev)
|
|
328
|
+
* const output = formatter.format(structuredError)
|
|
329
|
+
* ```
|
|
330
|
+
*/
|
|
331
|
+
export function createFormatter(format, isDev = true) {
|
|
332
|
+
switch (format) {
|
|
333
|
+
case 'json':
|
|
334
|
+
return new JsonErrorFormatter({
|
|
335
|
+
pretty: isDev,
|
|
336
|
+
includeSource: isDev,
|
|
337
|
+
includeContext: isDev,
|
|
338
|
+
includeFixes: true,
|
|
339
|
+
includeDocs: true,
|
|
340
|
+
});
|
|
341
|
+
case 'terminal':
|
|
342
|
+
return new TerminalErrorFormatter({
|
|
343
|
+
useColors: true,
|
|
344
|
+
showSnippet: true,
|
|
345
|
+
showFixes: true,
|
|
346
|
+
maxFixes: 3,
|
|
347
|
+
});
|
|
348
|
+
case 'inertia':
|
|
349
|
+
return new InertiaErrorFormatter({
|
|
350
|
+
includeFixes: isDev,
|
|
351
|
+
includeSource: isDev,
|
|
352
|
+
isDev,
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
}
|
|
@@ -0,0 +1,275 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Structured Error Types for Honertia
|
|
3
|
+
*
|
|
4
|
+
* World-class error system optimized for AI/LLM consumption.
|
|
5
|
+
* Every error includes machine-readable fix suggestions.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Error category for grouping related errors.
|
|
9
|
+
*/
|
|
10
|
+
export type ErrorCategory = 'validation' | 'auth' | 'resource' | 'configuration' | 'http' | 'database' | 'routing' | 'service' | 'internal';
|
|
11
|
+
/**
|
|
12
|
+
* Source location information from stack trace.
|
|
13
|
+
*/
|
|
14
|
+
export interface SourceLocation {
|
|
15
|
+
/** Original TypeScript file path */
|
|
16
|
+
file: string;
|
|
17
|
+
/** Line number (1-indexed) */
|
|
18
|
+
line: number;
|
|
19
|
+
/** Column number (1-indexed) */
|
|
20
|
+
column: number;
|
|
21
|
+
/** Function or method name if available */
|
|
22
|
+
functionName?: string;
|
|
23
|
+
/** Code snippet around the error */
|
|
24
|
+
codeSnippet?: CodeSnippet;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Code snippet for visual error display.
|
|
28
|
+
*/
|
|
29
|
+
export interface CodeSnippet {
|
|
30
|
+
/** Lines before the error line */
|
|
31
|
+
before: string[];
|
|
32
|
+
/** The line containing the error */
|
|
33
|
+
line: string;
|
|
34
|
+
/** Lines after the error line */
|
|
35
|
+
after: string[];
|
|
36
|
+
/** Character range to highlight */
|
|
37
|
+
highlight?: {
|
|
38
|
+
start: number;
|
|
39
|
+
end: number;
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Route information when error occurred.
|
|
44
|
+
*/
|
|
45
|
+
export interface RouteContext {
|
|
46
|
+
/** HTTP method */
|
|
47
|
+
method: string;
|
|
48
|
+
/** Route path pattern (e.g., "/projects/{project}") */
|
|
49
|
+
path: string;
|
|
50
|
+
/** Resolved route parameters */
|
|
51
|
+
params: Record<string, string>;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Handler information when error occurred.
|
|
55
|
+
*/
|
|
56
|
+
export interface HandlerContext {
|
|
57
|
+
/** Source file path */
|
|
58
|
+
file?: string;
|
|
59
|
+
/** Function or handler name */
|
|
60
|
+
function?: string;
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Request information when error occurred.
|
|
64
|
+
*/
|
|
65
|
+
export interface RequestContext {
|
|
66
|
+
/** Full request URL */
|
|
67
|
+
url: string;
|
|
68
|
+
/** Relevant headers (filtered for security) */
|
|
69
|
+
headers: Record<string, string>;
|
|
70
|
+
/** Request body for validation errors */
|
|
71
|
+
body?: unknown;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Service information when error occurred.
|
|
75
|
+
*/
|
|
76
|
+
export interface ServiceContext {
|
|
77
|
+
/** Service name (e.g., "DatabaseService") */
|
|
78
|
+
name: string;
|
|
79
|
+
/** Operation that was attempted */
|
|
80
|
+
operation?: string;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Complete context captured when an error occurs.
|
|
84
|
+
*/
|
|
85
|
+
export interface ErrorContext {
|
|
86
|
+
route?: RouteContext;
|
|
87
|
+
handler?: HandlerContext;
|
|
88
|
+
request?: RequestContext;
|
|
89
|
+
service?: ServiceContext;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Type of fix operation.
|
|
93
|
+
*/
|
|
94
|
+
export type FixType = 'add_code' | 'modify_code' | 'delete_code' | 'add_config' | 'install_dependency' | 'create_file' | 'run_command';
|
|
95
|
+
/**
|
|
96
|
+
* Position for code insertion/modification.
|
|
97
|
+
*/
|
|
98
|
+
export interface FixPosition {
|
|
99
|
+
/** Line number to insert at */
|
|
100
|
+
line?: number;
|
|
101
|
+
/** Column number */
|
|
102
|
+
column?: number;
|
|
103
|
+
/** Insert after this pattern */
|
|
104
|
+
after?: string;
|
|
105
|
+
/** Insert before this pattern */
|
|
106
|
+
before?: string;
|
|
107
|
+
/** Replace a range of lines */
|
|
108
|
+
replace?: {
|
|
109
|
+
startLine: number;
|
|
110
|
+
endLine: number;
|
|
111
|
+
};
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* A single fix operation.
|
|
115
|
+
*/
|
|
116
|
+
export interface FixOperation {
|
|
117
|
+
type: FixType;
|
|
118
|
+
/** File path for code changes */
|
|
119
|
+
file?: string;
|
|
120
|
+
/** Position for insertion */
|
|
121
|
+
position?: FixPosition;
|
|
122
|
+
/** Code or content to insert */
|
|
123
|
+
content?: string;
|
|
124
|
+
/** Config path for config changes (e.g., "honertia.database") */
|
|
125
|
+
configPath?: string;
|
|
126
|
+
/** Config value to set */
|
|
127
|
+
configValue?: unknown;
|
|
128
|
+
/** Command to run */
|
|
129
|
+
command?: string;
|
|
130
|
+
/** Package name for dependency installation */
|
|
131
|
+
package?: string;
|
|
132
|
+
/** Version constraint for dependency */
|
|
133
|
+
version?: string;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Action to take after applying a fix.
|
|
137
|
+
*/
|
|
138
|
+
export interface PostAction {
|
|
139
|
+
type: 'restart_server' | 'rebuild' | 'run_migrations' | 'clear_cache' | 'run_tests';
|
|
140
|
+
description: string;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* A suggested fix for an error.
|
|
144
|
+
*/
|
|
145
|
+
export interface FixSuggestion {
|
|
146
|
+
/** Unique identifier for this fix */
|
|
147
|
+
id: string;
|
|
148
|
+
/** Type of fix */
|
|
149
|
+
type: FixType;
|
|
150
|
+
/** Confidence level */
|
|
151
|
+
confidence: 'high' | 'medium' | 'low';
|
|
152
|
+
/** Human-readable description */
|
|
153
|
+
description: string;
|
|
154
|
+
/** Whether this can be applied automatically */
|
|
155
|
+
automated: boolean;
|
|
156
|
+
/** The fix operations to apply */
|
|
157
|
+
operations: FixOperation[];
|
|
158
|
+
/** Actions to take after applying */
|
|
159
|
+
postActions?: PostAction[];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Documentation reference for an error.
|
|
163
|
+
*/
|
|
164
|
+
export interface ErrorDocs {
|
|
165
|
+
/** URL to documentation */
|
|
166
|
+
url: string;
|
|
167
|
+
/** Related error codes */
|
|
168
|
+
related: string[];
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* The main structured error interface.
|
|
172
|
+
* This is the format returned for all Honertia errors.
|
|
173
|
+
*/
|
|
174
|
+
export interface HonertiaStructuredError {
|
|
175
|
+
/** Unique error code (e.g., "HON_VAL_001_FIELD_REQUIRED") */
|
|
176
|
+
code: string;
|
|
177
|
+
/** Effect tag for the error class */
|
|
178
|
+
tag: string;
|
|
179
|
+
/** Error category */
|
|
180
|
+
category: ErrorCategory;
|
|
181
|
+
/** Short human-readable title */
|
|
182
|
+
title: string;
|
|
183
|
+
/** Detailed error message */
|
|
184
|
+
message: string;
|
|
185
|
+
/** HTTP status code */
|
|
186
|
+
httpStatus: number;
|
|
187
|
+
/** Context when error occurred */
|
|
188
|
+
context: ErrorContext;
|
|
189
|
+
/** Source location from stack trace */
|
|
190
|
+
source?: SourceLocation;
|
|
191
|
+
/** Suggested fixes */
|
|
192
|
+
fixes: FixSuggestion[];
|
|
193
|
+
/** Documentation links */
|
|
194
|
+
docs?: ErrorDocs;
|
|
195
|
+
/** ISO 8601 timestamp */
|
|
196
|
+
timestamp: string;
|
|
197
|
+
/** Request correlation ID */
|
|
198
|
+
requestId?: string;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Extended error data for validation errors.
|
|
202
|
+
*/
|
|
203
|
+
export interface FieldError {
|
|
204
|
+
/** The invalid value that was provided */
|
|
205
|
+
value: unknown;
|
|
206
|
+
/** What was expected */
|
|
207
|
+
expected: string;
|
|
208
|
+
/** Human-readable error message */
|
|
209
|
+
message: string;
|
|
210
|
+
/** Path to the field (e.g., ["user", "address", "zip"]) */
|
|
211
|
+
path: string[];
|
|
212
|
+
/** Effect Schema type that failed */
|
|
213
|
+
schemaType?: string;
|
|
214
|
+
}
|
|
215
|
+
/**
|
|
216
|
+
* Validation-specific error extension.
|
|
217
|
+
*/
|
|
218
|
+
export interface ValidationErrorData {
|
|
219
|
+
/** Field-level errors */
|
|
220
|
+
fields: Record<string, FieldError>;
|
|
221
|
+
/** Inertia component to re-render */
|
|
222
|
+
component?: string;
|
|
223
|
+
}
|
|
224
|
+
/**
|
|
225
|
+
* Configuration-specific error extension.
|
|
226
|
+
*/
|
|
227
|
+
export interface ConfigurationErrorData {
|
|
228
|
+
/** The service that is missing */
|
|
229
|
+
missingService: string;
|
|
230
|
+
/** Configuration path (e.g., "honertia.database") */
|
|
231
|
+
configPath: string;
|
|
232
|
+
/** Setup function to use */
|
|
233
|
+
setupFunction: string;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* Route binding-specific error extension.
|
|
237
|
+
*/
|
|
238
|
+
export interface BindingErrorData {
|
|
239
|
+
/** Route parameter name */
|
|
240
|
+
param: string;
|
|
241
|
+
/** Database column being queried */
|
|
242
|
+
column: string;
|
|
243
|
+
/** Table name */
|
|
244
|
+
tableName: string;
|
|
245
|
+
/** The parameter value that failed */
|
|
246
|
+
value: string;
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* Error definition in the catalog.
|
|
250
|
+
*/
|
|
251
|
+
export interface ErrorDefinition {
|
|
252
|
+
/** Unique error code */
|
|
253
|
+
code: string;
|
|
254
|
+
/** Effect tag */
|
|
255
|
+
tag: string;
|
|
256
|
+
/** Error category */
|
|
257
|
+
category: ErrorCategory;
|
|
258
|
+
/** Short title */
|
|
259
|
+
title: string;
|
|
260
|
+
/** Message template with {placeholders} */
|
|
261
|
+
messageTemplate: string;
|
|
262
|
+
/** HTTP status code */
|
|
263
|
+
httpStatus: number;
|
|
264
|
+
/** Functions that generate fix suggestions */
|
|
265
|
+
defaultFixes: FixGenerator[];
|
|
266
|
+
/** Documentation path */
|
|
267
|
+
docsPath: string;
|
|
268
|
+
/** Related error codes */
|
|
269
|
+
related: string[];
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Function that generates a fix suggestion from context.
|
|
273
|
+
*/
|
|
274
|
+
export type FixGenerator = (context: ErrorContext, params: Record<string, unknown>) => FixSuggestion | null;
|
|
275
|
+
//# sourceMappingURL=error-types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"error-types.d.ts","sourceRoot":"","sources":["../../src/effect/error-types.ts"],"names":[],"mappings":"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"}
|