yinzerflow 0.2.5 → 0.2.7
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 +58 -0
- package/docs/advanced-configuration-options.md +116 -0
- package/docs/request.md +67 -18
- package/docs/routes.md +656 -0
- package/docs/start-here.md +178 -0
- package/example/README.md +11 -0
- package/example/app/handlers/example.ts +30 -0
- package/example/app/index.ts +112 -0
- package/example/app/routes/example.ts +18 -0
- package/example/app/routes/group-example.ts +13 -0
- package/example/app/util/customLogger.ts +166 -0
- package/example/docker-compose.yml +28 -0
- package/example/package.json +16 -0
- package/example/tsconfig.json +54 -0
- package/index.d.ts +19 -12
- package/index.js +10 -10
- package/index.js.map +5 -5
- package/package.json +3 -3
- package/docs/start-here.MD +0 -116
package/README.md
CHANGED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# YinzerFlow
|
|
2
|
+
|
|
3
|
+
A lightweight, modular HTTP server framework for Node.js built with TypeScript. Features comprehensive security protections, Pittsburgh personality, and flexible configuration options.
|
|
4
|
+
|
|
5
|
+
## 🚀 Quick Start
|
|
6
|
+
|
|
7
|
+
For complete documentation and examples, see **[docs/start-here.md](docs/start-here.md)**.
|
|
8
|
+
|
|
9
|
+
## 📦 Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
npm install yinzerflow
|
|
13
|
+
# or
|
|
14
|
+
bun add yinzerflow
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## 🔧 Basic Usage
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { YinzerFlow } from 'yinzerflow';
|
|
21
|
+
|
|
22
|
+
const app = new YinzerFlow({ port: 3000 });
|
|
23
|
+
|
|
24
|
+
app.get('/hello', () => {
|
|
25
|
+
return { message: 'Hello, World!' };
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
await app.listen();
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
## ✨ Features
|
|
32
|
+
|
|
33
|
+
- **Security-first** - Built-in protections against common web vulnerabilities
|
|
34
|
+
- **TypeScript-first** - Full type safety and IntelliSense support
|
|
35
|
+
- **Pittsburgh personality** - Witty logging and error messages
|
|
36
|
+
- **Flexible configuration** - Comprehensive options for different use cases
|
|
37
|
+
- **Modular architecture** - Scales from simple APIs to complex applications
|
|
38
|
+
|
|
39
|
+
## 📚 Documentation
|
|
40
|
+
|
|
41
|
+
- **[Getting Started](docs/start-here.md)** - Complete guide and examples
|
|
42
|
+
- **[Routes](docs/routes.md)** - Routing system and handlers
|
|
43
|
+
- **[Request/Response](docs/request.md)** - Request and response objects
|
|
44
|
+
- **[Logging](docs/logging.md)** - Logging configuration and customization
|
|
45
|
+
- **[Advanced Configuration](docs/advanced-configuration-options.md)** - Detailed configuration options
|
|
46
|
+
|
|
47
|
+
## 🛡️ Security
|
|
48
|
+
|
|
49
|
+
YinzerFlow includes comprehensive security features:
|
|
50
|
+
- IP security and rate limiting
|
|
51
|
+
- CORS protection
|
|
52
|
+
- Body parsing with security limits
|
|
53
|
+
- Header validation and sanitization
|
|
54
|
+
- Prototype pollution protection
|
|
55
|
+
|
|
56
|
+
## 📄 License
|
|
57
|
+
|
|
58
|
+
MIT License - see [LICENSE](LICENSE) for details.
|
|
@@ -90,6 +90,122 @@ const app = new YinzerFlow({
|
|
|
90
90
|
| `keepAliveTimeout` | `number` | `65000` | Keep-alive timeout |
|
|
91
91
|
| `headersTimeout` | `number` | `66000` | Headers timeout (should be > keep-alive) |
|
|
92
92
|
|
|
93
|
+
### Graceful Shutdown Configuration
|
|
94
|
+
|
|
95
|
+
Control automatic graceful shutdown behavior:
|
|
96
|
+
|
|
97
|
+
```typescript
|
|
98
|
+
const app = new YinzerFlow({
|
|
99
|
+
port: 3000,
|
|
100
|
+
autoGracefulShutdown: true, // Enable automatic signal handling (default)
|
|
101
|
+
});
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
| Option | Type | Default | Description |
|
|
105
|
+
|-----|---|---|---|
|
|
106
|
+
| `autoGracefulShutdown` | `boolean` | `true` | Enable automatic SIGTERM/SIGINT handling |
|
|
107
|
+
|
|
108
|
+
**When enabled (default):**
|
|
109
|
+
- Automatically sets up SIGTERM and SIGINT signal handlers
|
|
110
|
+
- Logs shutdown process with Pittsburgh personality
|
|
111
|
+
- Calls `app.close()` and `process.exit(0)` automatically
|
|
112
|
+
- Prevents duplicate handlers when multiple instances are created
|
|
113
|
+
|
|
114
|
+
**When disabled:**
|
|
115
|
+
- No automatic signal handling
|
|
116
|
+
- Manual graceful shutdown setup required
|
|
117
|
+
- Useful for custom shutdown logic or integration with process managers
|
|
118
|
+
|
|
119
|
+
### Custom Graceful Shutdown Example
|
|
120
|
+
|
|
121
|
+
When `autoGracefulShutdown: false`, you can implement custom shutdown logic:
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
import { YinzerFlow } from 'yinzerflow';
|
|
125
|
+
|
|
126
|
+
const app = new YinzerFlow({
|
|
127
|
+
port: 3000,
|
|
128
|
+
autoGracefulShutdown: false, // Disable automatic handling
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// Custom shutdown with additional cleanup
|
|
132
|
+
const gracefulShutdown = async (signal: string) => {
|
|
133
|
+
console.log(`🛑 Received ${signal}, starting custom shutdown...`);
|
|
134
|
+
|
|
135
|
+
// Custom cleanup logic
|
|
136
|
+
await cleanupDatabase();
|
|
137
|
+
await saveApplicationState();
|
|
138
|
+
|
|
139
|
+
// Close the server
|
|
140
|
+
await app.close();
|
|
141
|
+
|
|
142
|
+
console.log('✅ Custom shutdown completed');
|
|
143
|
+
process.exit(0);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Set up custom signal handlers
|
|
147
|
+
process.on('SIGTERM', () => gracefulShutdown('SIGTERM'));
|
|
148
|
+
process.on('SIGINT', () => gracefulShutdown('SIGINT'));
|
|
149
|
+
|
|
150
|
+
await app.listen();
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Advanced Custom Shutdown Example
|
|
154
|
+
|
|
155
|
+
For complex applications with multiple cleanup steps:
|
|
156
|
+
|
|
157
|
+
```typescript
|
|
158
|
+
import { YinzerFlow } from 'yinzerflow';
|
|
159
|
+
|
|
160
|
+
const app = new YinzerFlow({
|
|
161
|
+
port: 3000,
|
|
162
|
+
autoGracefulShutdown: false,
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
let isShuttingDown = false;
|
|
166
|
+
|
|
167
|
+
const advancedShutdown = async (signal: string) => {
|
|
168
|
+
if (isShuttingDown) {
|
|
169
|
+
console.log('⚠️ Shutdown already in progress, ignoring signal');
|
|
170
|
+
return;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
isShuttingDown = true;
|
|
174
|
+
console.log(`🛑 Received ${signal}, starting advanced shutdown...`);
|
|
175
|
+
|
|
176
|
+
try {
|
|
177
|
+
// Phase 1: Stop accepting new requests
|
|
178
|
+
console.log('📝 Phase 1: Stopping new requests...');
|
|
179
|
+
// Your logic here
|
|
180
|
+
|
|
181
|
+
// Phase 2: Complete in-flight requests
|
|
182
|
+
console.log('📝 Phase 2: Completing in-flight requests...');
|
|
183
|
+
await waitForInFlightRequests();
|
|
184
|
+
|
|
185
|
+
// Phase 3: Cleanup resources
|
|
186
|
+
console.log('📝 Phase 3: Cleaning up resources...');
|
|
187
|
+
await cleanupDatabase();
|
|
188
|
+
await closeFileHandles();
|
|
189
|
+
await flushLogs();
|
|
190
|
+
|
|
191
|
+
// Phase 4: Close server
|
|
192
|
+
console.log('📝 Phase 4: Closing server...');
|
|
193
|
+
await app.close();
|
|
194
|
+
|
|
195
|
+
console.log('✅ Advanced shutdown completed successfully');
|
|
196
|
+
process.exit(0);
|
|
197
|
+
} catch (error) {
|
|
198
|
+
console.error('❌ Shutdown failed:', error);
|
|
199
|
+
process.exit(1);
|
|
200
|
+
}
|
|
201
|
+
};
|
|
202
|
+
|
|
203
|
+
process.on('SIGTERM', () => advancedShutdown('SIGTERM'));
|
|
204
|
+
process.on('SIGINT', () => advancedShutdown('SIGINT'));
|
|
205
|
+
|
|
206
|
+
await app.listen();
|
|
207
|
+
```
|
|
208
|
+
|
|
93
209
|
### Logging Configuration
|
|
94
210
|
|
|
95
211
|
Control framework logging output with built-in Pittsburgh personality or custom logging libraries. See [Logging Documentation](./logging.md) for detailed setup, custom logger integration, and advanced use cases.
|
package/docs/request.md
CHANGED
|
@@ -36,7 +36,9 @@ YinzerFlow's request parsing includes built-in security limits that are automati
|
|
|
36
36
|
|
|
37
37
|
These limits are built into the framework and cannot be disabled, ensuring consistent security across all YinzerFlow applications.
|
|
38
38
|
|
|
39
|
-
##
|
|
39
|
+
## Examples
|
|
40
|
+
|
|
41
|
+
### Basic Example
|
|
40
42
|
|
|
41
43
|
```typescript
|
|
42
44
|
import { YinzerFlow } from 'yinzerflow';
|
|
@@ -56,6 +58,9 @@ app.post('/api/users/:id', ({ request }) => {
|
|
|
56
58
|
|
|
57
59
|
// Access request body
|
|
58
60
|
const userData = request.body;
|
|
61
|
+
|
|
62
|
+
// Access raw body for manual parsing when needed
|
|
63
|
+
const rawBody = request.rawBody;
|
|
59
64
|
|
|
60
65
|
const clientIp = request.ipAddress
|
|
61
66
|
|
|
@@ -68,7 +73,67 @@ app.post('/api/users/:id', ({ request }) => {
|
|
|
68
73
|
receivedData: userData
|
|
69
74
|
};
|
|
70
75
|
});
|
|
71
|
-
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Body Parsing Example
|
|
79
|
+
|
|
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.
|
|
81
|
+
|
|
82
|
+
```typescript
|
|
83
|
+
app.post('/api/users', ({ request, response }) => {
|
|
84
|
+
// Body is automatically parsed based on Content-Type
|
|
85
|
+
const userData = request.body;
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
message: 'User created successfully',
|
|
89
|
+
data: userData
|
|
90
|
+
};
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Raw Body Access Example
|
|
95
|
+
|
|
96
|
+
For advanced use cases where you need to manually parse the request body, YinzerFlow provides access to the raw body via `request.rawBody`. This is useful when:
|
|
97
|
+
|
|
98
|
+
- You need to implement custom parsing logic
|
|
99
|
+
- You want to validate the raw body before parsing
|
|
100
|
+
- You're working with unsupported content types
|
|
101
|
+
- You need to implement custom security validations
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
app.post('/api/custom-parser', ({ request }) => {
|
|
105
|
+
// Access the raw body as string or Buffer
|
|
106
|
+
const rawBody = request.rawBody;
|
|
107
|
+
|
|
108
|
+
// Implement custom parsing logic
|
|
109
|
+
if (typeof rawBody === 'string') {
|
|
110
|
+
// Custom string parsing
|
|
111
|
+
const customData = parseCustomFormat(rawBody);
|
|
112
|
+
return { parsed: customData };
|
|
113
|
+
} else if (Buffer.isBuffer(rawBody)) {
|
|
114
|
+
// Custom binary parsing
|
|
115
|
+
const binaryData = parseBinaryFormat(rawBody);
|
|
116
|
+
return { parsed: binaryData };
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
return { error: 'Unsupported body format' };
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
// Example: Custom XML parser
|
|
123
|
+
app.post('/api/xml', ({ request }) => {
|
|
124
|
+
const rawBody = request.rawBody;
|
|
125
|
+
|
|
126
|
+
if (typeof rawBody === 'string') {
|
|
127
|
+
// Parse XML manually
|
|
128
|
+
const xmlData = parseXML(rawBody);
|
|
129
|
+
return { xml: xmlData };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
return { error: 'Expected string body for XML' };
|
|
133
|
+
});
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
**Note**: The `rawBody` property contains the unprocessed request body as either a `string` or `Buffer`, depending on the content type and framework processing. Always validate and sanitize raw body data before processing to prevent security vulnerabilities.
|
|
72
137
|
|
|
73
138
|
## Common Use Cases
|
|
74
139
|
|
|
@@ -126,20 +191,4 @@ YinzerFlow implements several security measures to prevent common request-based
|
|
|
126
191
|
- **Problem**: Spoofed proxy headers can bypass IP-based security controls
|
|
127
192
|
- **YinzerFlow Solution**: Secure IP address extraction with proxy header validation prevents spoofing attacks
|
|
128
193
|
|
|
129
|
-
## Body Parsing
|
|
130
|
-
|
|
131
|
-
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.
|
|
132
|
-
|
|
133
|
-
```typescript
|
|
134
|
-
app.post('/api/users', ({ request, response }) => {
|
|
135
|
-
// Body is automatically parsed based on Content-Type
|
|
136
|
-
const userData = request.body;
|
|
137
|
-
|
|
138
|
-
return {
|
|
139
|
-
message: 'User created successfully',
|
|
140
|
-
data: userData
|
|
141
|
-
};
|
|
142
|
-
});
|
|
143
|
-
```
|
|
144
|
-
|
|
145
194
|
These security measures ensure YinzerFlow's request implementation follows security best practices and prevents common attack vectors while maintaining RFC compliance and performance.
|