yinzerflow 0.2.8 → 0.2.9

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.
@@ -0,0 +1,293 @@
1
+ # Error Handling
2
+
3
+ YinzerFlow provides comprehensive error handling with automatic error catching and custom error handlers. The framework automatically catches all errors thrown in route handlers, hooks, and middleware, ensuring your application never crashes due to unhandled exceptions.
4
+
5
+ ## Configuration
6
+
7
+ Error handling is automatically enabled and requires no configuration for basic usage:
8
+
9
+ ```typescript
10
+ import { YinzerFlow } from 'yinzerflow';
11
+
12
+ const app = new YinzerFlow({ port: 3000 });
13
+
14
+ // Errors are automatically caught - no configuration needed
15
+ app.get('/api/users/:id', async ({ request }) => {
16
+ const user = await database.findUser(request.params.id);
17
+ if (!user) {
18
+ throw new Error('User not found'); // Automatically handled
19
+ }
20
+ return user;
21
+ });
22
+ ```
23
+
24
+ ### Configuration Options
25
+
26
+ YinzerFlow's error handling includes built-in security and logging features:
27
+
28
+ | Feature | Default | Description |
29
+ |---------|---------|-------------|
30
+ | **Automatic Error Catching** | Enabled | All errors in handlers are automatically caught |
31
+ | **Default Error Response** | 500 Internal Server Error | Structured error response with logging |
32
+ | **Error Logging** | Enabled | All errors logged with Pittsburgh personality |
33
+ | **CORS Headers** | Automatic | Error responses include proper CORS headers |
34
+ | **Fallback Protection** | Enabled | Safe fallback if custom handlers fail |
35
+
36
+ ## Examples
37
+
38
+ ### Basic Example
39
+
40
+ ```typescript
41
+ import { YinzerFlow } from 'yinzerflow';
42
+
43
+ const app = new YinzerFlow({ port: 3000 });
44
+
45
+ // No try-catch needed - errors are automatically handled
46
+ app.get('/api/users/:id', async (ctx) => {
47
+ const userId = ctx.request.params.id;
48
+
49
+ // Database errors are automatically caught
50
+ const user = await database.findUser(userId);
51
+
52
+ if (!user) {
53
+ // This error will be handled by your error handler
54
+ throw new Error('User not found');
55
+ }
56
+
57
+ return user;
58
+ });
59
+
60
+ // Custom error handler
61
+ app.onError((ctx, error) => {
62
+ ctx.response.setStatusCode(500);
63
+ return {
64
+ success: false,
65
+ message: 'Something went wrong',
66
+ timestamp: new Date().toISOString()
67
+ };
68
+ });
69
+
70
+ await app.listen();
71
+ ```
72
+
73
+ See [Error Handler Pattern](./examples.md#error-handler-pattern) for a complete error handler example.
74
+
75
+ ### Advanced Example
76
+
77
+ ```typescript
78
+ import { YinzerFlow } from 'yinzerflow';
79
+
80
+ const app = new YinzerFlow({ port: 3000 });
81
+
82
+ // Custom error handler with different error types
83
+ app.onError((ctx, error) => {
84
+ // Handle different error types
85
+ if (error instanceof ValidationError) {
86
+ ctx.response.setStatusCode(400);
87
+ return {
88
+ success: false,
89
+ error: 'Validation failed',
90
+ details: error.details,
91
+ path: ctx.request.path
92
+ };
93
+ }
94
+
95
+ if (error instanceof DatabaseError) {
96
+ ctx.response.setStatusCode(503);
97
+ return {
98
+ success: false,
99
+ error: 'Service temporarily unavailable',
100
+ retryAfter: 30
101
+ };
102
+ }
103
+
104
+ if (error instanceof AuthenticationError) {
105
+ ctx.response.setStatusCode(401);
106
+ return {
107
+ success: false,
108
+ error: 'Authentication required',
109
+ code: 'UNAUTHORIZED'
110
+ };
111
+ }
112
+
113
+ // Default error handling
114
+ ctx.response.setStatusCode(500);
115
+ return {
116
+ success: false,
117
+ error: 'Internal server error',
118
+ requestId: ctx.request.headers['x-request-id'] || 'unknown'
119
+ };
120
+ });
121
+
122
+ // Custom not found handler
123
+ app.onNotFound((ctx) => {
124
+ ctx.response.setStatusCode(404);
125
+ return {
126
+ success: false,
127
+ error: 'Route not found',
128
+ path: ctx.request.path,
129
+ method: ctx.request.method,
130
+ availableMethods: ['GET', 'POST', 'PUT', 'DELETE']
131
+ };
132
+ });
133
+
134
+ await app.listen();
135
+ ```
136
+
137
+ ## Common Use Cases
138
+
139
+ - **Database Error Handling**: Automatically catch and handle database connection errors, query failures, and constraint violations
140
+ - **Validation Error Processing**: Handle input validation errors with structured error responses and field-specific messages
141
+ - **Authentication Error Management**: Process authentication failures, expired tokens, and authorization errors with appropriate status codes
142
+ - **External API Error Handling**: Catch and handle errors from third-party services with retry logic and fallback responses
143
+ - **File Upload Error Processing**: Handle file size limits, type validation errors, and upload failures with user-friendly messages
144
+ - **Rate Limiting Error Responses**: Process rate limit violations with appropriate headers and retry information
145
+
146
+ ## Error Handler Parameters
147
+
148
+ The error handler receives two parameters:
149
+
150
+ ### Context Object (`ctx`)
151
+ The complete request context containing `request` and `response` objects. See [Context Object Documentation](./context.md) for detailed information about accessing context properties.
152
+
153
+ ### Error Object (`error`)
154
+ The caught error can be any type - Error instances, strings, objects, or other values:
155
+
156
+ ```typescript
157
+ app.onError((ctx, error) => {
158
+ // Handle different error types
159
+ if (error instanceof Error) {
160
+ return { error: error.message, stack: error.stack };
161
+ } else if (typeof error === 'string') {
162
+ return { error };
163
+ } else if (typeof error === 'object' && error !== null) {
164
+ return { error: JSON.stringify(error) };
165
+ } else {
166
+ return { error: 'Unknown error occurred' };
167
+ }
168
+ });
169
+ ```
170
+
171
+ ## Error Handler Best Practices
172
+
173
+ ### Structured Error Responses
174
+ ```typescript
175
+ app.onError((ctx, error) => {
176
+ const errorResponse = {
177
+ success: false,
178
+ message: error instanceof Error ? error.message : 'Internal server error',
179
+ timestamp: new Date().toISOString(),
180
+ path: ctx.request.path,
181
+ method: ctx.request.method,
182
+ requestId: ctx.request.headers['x-request-id'] || 'unknown'
183
+ };
184
+
185
+ ctx.response.setStatusCode(500);
186
+ return errorResponse;
187
+ });
188
+ ```
189
+
190
+ ### Error Type Handling
191
+ ```typescript
192
+ app.onError((ctx, error) => {
193
+ // Handle specific error types
194
+ if (error instanceof ValidationError) {
195
+ ctx.response.setStatusCode(400);
196
+ return {
197
+ success: false,
198
+ error: 'Validation failed',
199
+ details: error.details,
200
+ fields: error.fields
201
+ };
202
+ }
203
+
204
+ if (error instanceof DatabaseError) {
205
+ ctx.response.setStatusCode(503);
206
+ return {
207
+ success: false,
208
+ error: 'Database connection failed',
209
+ retryAfter: 60
210
+ };
211
+ }
212
+
213
+ if (error instanceof RateLimitError) {
214
+ ctx.response.setStatusCode(429);
215
+ return {
216
+ success: false,
217
+ error: 'Too many requests',
218
+ retryAfter: error.retryAfter
219
+ };
220
+ }
221
+
222
+ // Default handling
223
+ ctx.response.setStatusCode(500);
224
+ return { success: false, error: 'Internal server error' };
225
+ });
226
+ ```
227
+
228
+ ### Error Logging and Monitoring
229
+ ```typescript
230
+ app.onError((ctx, error) => {
231
+ // Log detailed error information for debugging
232
+ const errorInfo = {
233
+ message: error instanceof Error ? error.message : String(error),
234
+ stack: error instanceof Error ? error.stack : undefined,
235
+ path: ctx.request.path,
236
+ method: ctx.request.method,
237
+ userAgent: ctx.request.headers['user-agent'],
238
+ ipAddress: ctx.request.ipAddress,
239
+ timestamp: new Date().toISOString(),
240
+ requestId: ctx.request.headers['x-request-id'] || 'unknown'
241
+ };
242
+
243
+ // Log to monitoring service (but don't expose to client)
244
+ console.error('Application error:', errorInfo);
245
+
246
+ // Return sanitized response to client
247
+ ctx.response.setStatusCode(500);
248
+ return {
249
+ success: false,
250
+ error: 'Internal server error',
251
+ requestId: errorInfo.requestId
252
+ };
253
+ });
254
+ ```
255
+
256
+ ## Error Handler Limitations
257
+
258
+ - **No Error Throwing**: Error handlers should not throw errors - use return statements instead
259
+ - **Response Object**: Return a response object that will be sent to the client
260
+ - **Status Code**: Set the status code on `ctx.response.setStatusCode()` before returning
261
+ - **CORS Headers**: CORS headers are automatically added to error responses
262
+ - **Async Support**: Error handlers can be async functions
263
+ - **Hook Integration**: Error handlers work with before/after hooks
264
+
265
+ ## Security Considerations
266
+
267
+ YinzerFlow implements several security measures to prevent common error handling vulnerabilities:
268
+
269
+ ### 🛡️ Error Information Sanitization
270
+ - **Problem**: Detailed error information can expose sensitive data like database credentials, file paths, or internal structure
271
+ - **YinzerFlow Solution**: Error handlers receive the raw error but should return sanitized responses to clients
272
+
273
+ ### 🛡️ Stack Trace Protection
274
+ - **Problem**: Stack traces in production can reveal application structure and sensitive information
275
+ - **YinzerFlow Solution**: Error handlers can access stack traces for logging but should not return them to clients
276
+
277
+ ### 🛡️ Error Logging Security
278
+ - **Problem**: Logged errors can contain sensitive information that could be exploited
279
+ - **YinzerFlow Solution**: Built-in logging with Pittsburgh personality, custom loggers can implement additional sanitization
280
+
281
+ ### 🛡️ CORS Error Response Protection
282
+ - **Problem**: Error responses without CORS headers can cause client-side issues
283
+ - **YinzerFlow Solution**: CORS headers are automatically added to all error responses
284
+
285
+ ### 🛡️ Fallback Error Protection
286
+ - **Problem**: If custom error handlers fail, applications can crash or expose sensitive information
287
+ - **YinzerFlow Solution**: Built-in fallback error handler ensures graceful degradation
288
+
289
+ ### 🛡️ Error Handler Isolation
290
+ - **Problem**: Malicious error handlers could modify responses or bypass security controls
291
+ - **YinzerFlow Solution**: Error handlers are isolated and failures don't affect core functionality
292
+
293
+ These security measures ensure YinzerFlow's error handling implementation follows security best practices and prevents common attack vectors while maintaining application stability and user experience.
@@ -0,0 +1,195 @@
1
+ # Common Examples
2
+
3
+ This file contains shared examples that are referenced throughout the YinzerFlow documentation to avoid duplication.
4
+
5
+ ## Basic Handler Pattern
6
+
7
+ ```typescript
8
+ import { YinzerFlow } from 'yinzerflow';
9
+
10
+ const app = new YinzerFlow({ port: 3000 });
11
+
12
+ app.post('/api/users/:id', (ctx) => {
13
+ // Access request properties
14
+ const userId = ctx.request.params.id;
15
+ const userData = ctx.request.body;
16
+ const includeProfile = ctx.request.query.include_profile;
17
+ const authHeader = ctx.request.headers['authorization'];
18
+ const clientIp = ctx.request.ipAddress;
19
+
20
+ // Control response
21
+ ctx.response.setStatusCode(201);
22
+ ctx.response.addHeaders({
23
+ 'Location': `/api/users/${userId}`,
24
+ 'X-User-ID': userId
25
+ });
26
+
27
+ return {
28
+ id: userId,
29
+ data: userData,
30
+ includeProfile: !!includeProfile,
31
+ clientIp
32
+ };
33
+ });
34
+ ```
35
+
36
+ ## Request Access Pattern
37
+
38
+ ```typescript
39
+ app.get('/api/users/:id', (ctx) => {
40
+ const { request } = ctx;
41
+
42
+ // Access route parameters
43
+ const userId = request.params.id;
44
+
45
+ // Access query parameters
46
+ const includeProfile = request.query.include_profile;
47
+
48
+ // Access headers
49
+ const contentType = request.headers['content-type'];
50
+ const authorization = request.headers['authorization'];
51
+
52
+ // Access request body
53
+ const userData = request.body;
54
+
55
+ // Access raw body for manual parsing when needed
56
+ const rawBody = request.rawBody;
57
+
58
+ const clientIp = request.ipAddress
59
+
60
+ return {
61
+ message: 'Request processed successfully',
62
+ userId,
63
+ includeProfile,
64
+ contentType,
65
+ hasAuth: !!authorization,
66
+ receivedData: userData
67
+ };
68
+ });
69
+ ```
70
+
71
+ ## Response Control Pattern
72
+
73
+ ```typescript
74
+ app.get('/api/users/:id', (ctx) => {
75
+ const { request, response } = ctx;
76
+ const userId = request.params.id;
77
+
78
+ // Set successful status code
79
+ response.setStatusCode(200);
80
+
81
+ // Add custom headers
82
+ response.addHeaders({
83
+ 'X-User-ID': userId,
84
+ 'Cache-Control': 'max-age=3600',
85
+ 'X-API-Version': '1.0'
86
+ });
87
+
88
+ // Return JSON response body (Content-Type automatically set)
89
+ return {
90
+ id: userId,
91
+ name: 'John Doe',
92
+ email: 'john@example.com',
93
+ timestamp: new Date().toISOString()
94
+ };
95
+ });
96
+ ```
97
+
98
+ ## Error Handler Pattern
99
+
100
+ ```typescript
101
+ app.onError((ctx, error) => {
102
+ // Access request context in error handler
103
+ const { path, method, headers } = ctx.request;
104
+
105
+ // Control error response
106
+ ctx.response.setStatusCode(500);
107
+
108
+ return {
109
+ success: false,
110
+ error: 'Internal server error',
111
+ path,
112
+ method,
113
+ timestamp: new Date().toISOString()
114
+ };
115
+ });
116
+ ```
117
+
118
+ ## Hook Pattern
119
+
120
+ ```typescript
121
+ // Before hook
122
+ app.beforeAll([(ctx) => {
123
+ // Access request context
124
+ const authHeader = ctx.request.headers['authorization'];
125
+
126
+ // Validate authentication
127
+ if (!authHeader) {
128
+ throw new Error('Authentication required');
129
+ }
130
+ }]);
131
+
132
+ // After hook
133
+ app.afterAll([(ctx) => {
134
+ // Access response context
135
+ ctx.response.addHeaders({
136
+ 'X-Response-Time': Date.now().toString()
137
+ });
138
+ }]);
139
+ ```
140
+
141
+ ## TypeScript Pattern
142
+
143
+ ```typescript
144
+ import type { HandlerCallback } from 'yinzerflow';
145
+
146
+ // Define custom types for your API
147
+ interface UserBody {
148
+ name: string;
149
+ email: string;
150
+ age: number;
151
+ }
152
+
153
+ interface UserResponse {
154
+ id: string;
155
+ name: string;
156
+ email: string;
157
+ createdAt: string;
158
+ }
159
+
160
+ interface UserQuery {
161
+ include_profile?: string;
162
+ limit?: string;
163
+ }
164
+
165
+ interface UserParams {
166
+ id: string;
167
+ }
168
+
169
+ // Typed handler with custom body, response, query, and params
170
+ const createUserHandler: HandlerCallback<{
171
+ body: UserBody;
172
+ response: UserResponse;
173
+ query: UserQuery;
174
+ params: UserParams;
175
+ }> = (ctx) => {
176
+ // ctx.request.body is typed as UserBody
177
+ const userData = ctx.request.body;
178
+
179
+ // ctx.request.query is typed as UserQuery
180
+ const includeProfile = ctx.request.query.include_profile;
181
+
182
+ // ctx.request.params is typed as UserParams
183
+ const userId = ctx.request.params.id;
184
+
185
+ // Return type is typed as UserResponse
186
+ return {
187
+ id: 'user-123',
188
+ name: userData.name,
189
+ email: userData.email,
190
+ createdAt: new Date().toISOString()
191
+ };
192
+ };
193
+
194
+ app.post('/api/users/:id', createUserHandler);
195
+ ```
@@ -40,44 +40,11 @@ These limits are built into the framework and cannot be disabled, ensuring consi
40
40
 
41
41
  ### Basic Example
42
42
 
43
- ```typescript
44
- import { YinzerFlow } from 'yinzerflow';
45
-
46
- const app = new YinzerFlow({ port: 3000 });
47
-
48
- app.post('/api/users/:id', ({ request }) => {
49
- // Access route parameters
50
- const userId = request.params.id;
51
-
52
- // Access query parameters
53
- const includeProfile = request.query.include_profile;
54
-
55
- // Access headers
56
- const contentType = request.headers['content-type'];
57
- const authorization = request.headers['authorization'];
58
-
59
- // Access request body
60
- const userData = request.body;
61
-
62
- // Access raw body for manual parsing when needed
63
- const rawBody = request.rawBody;
64
-
65
- const clientIp = request.ipAddress
66
-
67
- return {
68
- message: 'Request processed successfully',
69
- userId,
70
- includeProfile,
71
- contentType,
72
- hasAuth: !!authorization,
73
- receivedData: userData
74
- };
75
- });
76
- ```
43
+ See [Request Access Pattern](./examples.md#request-access-pattern) for a complete example showing how to access request properties.
77
44
 
78
45
  ### Body Parsing Example
79
46
 
80
- YinzerFlow automatically parses request bodies (JSON, file uploads, forms) with built-in security protections. Parsed data is available on `request.body` - see [Body Parsing Documentation](./body-parsing.md) for detailed configuration options, examples, and security considerations.
47
+ YinzerFlow automatically parses request bodies (JSON, file uploads, forms) with built-in security protections. Parsed data is available on `request.body` - see [Body Parsing Documentation](../security/body-parsing.md) for detailed configuration options, examples, and security considerations.
81
48
 
82
49
  ```typescript
83
50
  app.post('/api/users', ({ request, response }) => {
@@ -155,7 +122,7 @@ YinzerFlow automatically handles request parsing errors and provides clear error
155
122
  - `Header value too long: maximum 8192 characters allowed`
156
123
  - `Header value contains invalid control characters`
157
124
 
158
- **Body parsing errors:** See [Body Parsing Documentation](./body-parsing.md) for detailed error handling
125
+ **Body parsing errors:** See [Body Parsing Documentation](../security/body-parsing.md) for detailed error handling
159
126
 
160
127
  These errors automatically result in appropriate HTTP status codes (400 Bad Request) and prevent malformed requests from reaching your application handlers.
161
128
 
@@ -30,46 +30,7 @@ YinzerFlow's response handling includes built-in security protections that are a
30
30
 
31
31
  ## Basic Example
32
32
 
33
- ```typescript
34
- import { YinzerFlow } from 'yinzerflow';
35
-
36
- const app = new YinzerFlow({ port: 3000 });
37
-
38
- app.get('/api/users/:id', ({ request, response }) => {
39
- const userId = request.params.id;
40
-
41
- // Set successful status code
42
- response.setStatusCode(200);
43
-
44
- // Add custom headers
45
- response.addHeaders({
46
- 'X-User-ID': userId,
47
- 'Cache-Control': 'max-age=3600',
48
- 'X-API-Version': '1.0'
49
- });
50
-
51
- // Return JSON response body (Content-Type automatically set)
52
- return {
53
- id: userId,
54
- name: 'John Doe',
55
- email: 'john@example.com',
56
- timestamp: new Date().toISOString()
57
- };
58
- });
59
-
60
- app.post('/api/files', ({ request, response }) => {
61
- // Set created status
62
- response.setStatusCode(201);
63
-
64
- // Add location header for created resource
65
- response.addHeaders({
66
- 'Location': '/api/files/12345',
67
- 'X-Upload-Size': request.headers['content-length'] || '0'
68
- });
69
-
70
- return { fileId: '12345', status: 'uploaded' };
71
- });
72
- ```
33
+ See [Response Control Pattern](./examples.md#response-control-pattern) for a complete example showing how to control the response.
73
34
 
74
35
  ## Response Body Handling
75
36