yinzerflow 0.2.8 → 0.2.10
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/docs/{advanced-configuration-options.md → configuration/advanced-configuration-options.md} +2 -0
- package/docs/configuration/configuration-patterns.md +500 -0
- package/docs/core/context.md +92 -0
- package/docs/core/error-handling.md +293 -0
- package/docs/core/examples.md +195 -0
- package/docs/{request.md → core/request.md} +3 -36
- package/docs/{response.md → core/response.md} +1 -40
- package/docs/{routes.md → core/routes.md} +17 -116
- package/docs/quick-reference.md +346 -0
- package/docs/{body-parsing.md → security/body-parsing.md} +3 -1
- package/docs/{cors.md → security/cors.md} +3 -1
- package/docs/{ip-security.md → security/ip-security.md} +3 -1
- package/docs/security/security-overview.md +282 -0
- package/docs/start-here.md +14 -8
- package/example/app/handlers/example.ts +2 -0
- package/example/app/index.ts +7 -7
- package/index.d.ts +3 -2
- package/index.js +4 -4
- package/index.js.map +6 -6
- package/package.json +1 -1
- /package/docs/{logging.md → security/logging.md} +0 -0
|
@@ -0,0 +1,282 @@
|
|
|
1
|
+
# Security Overview
|
|
2
|
+
|
|
3
|
+
YinzerFlow implements a comprehensive security-first approach with built-in protections against common web vulnerabilities. This overview covers the key security features and how they work together to protect your applications.
|
|
4
|
+
|
|
5
|
+
## Security Architecture
|
|
6
|
+
|
|
7
|
+
YinzerFlow's security is built on multiple layers of protection:
|
|
8
|
+
|
|
9
|
+
```
|
|
10
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
11
|
+
│ Application Layer │
|
|
12
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
|
13
|
+
│ │ Route Security│ │ Error Handling │ │ Logging │ │
|
|
14
|
+
│ │ - Validation │ │ - Catching │ │ - Audit │ │
|
|
15
|
+
│ │ - Sanitization│ │ - Reporting │ │ - Monitor │ │
|
|
16
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
|
17
|
+
└─────────────────────────────────────────────────────────────┘
|
|
18
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
19
|
+
│ Framework Layer │
|
|
20
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
|
21
|
+
│ │ Body Parsing │ │ CORS │ │ IP Security │ │
|
|
22
|
+
│ │ - DoS Protection│ │ - Origin Valid │ │ - Spoofing │ │
|
|
23
|
+
│ │ - Size Limits │ │ - Headers │ │ - Detection │ │
|
|
24
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
|
25
|
+
└─────────────────────────────────────────────────────────────┘
|
|
26
|
+
┌─────────────────────────────────────────────────────────────┐
|
|
27
|
+
│ Network Layer │
|
|
28
|
+
│ ┌─────────────────┐ ┌─────────────────┐ ┌─────────────┐ │
|
|
29
|
+
│ │ HTTP Headers │ │ Request Size │ │ Timeouts │ │
|
|
30
|
+
│ │ - Validation │ │ - Limits │ │ - Limits │ │
|
|
31
|
+
│ │ - Sanitization│ │ - Protection │ │ - Graceful │ │
|
|
32
|
+
│ └─────────────────┘ └─────────────────┘ └─────────────┘ │
|
|
33
|
+
└─────────────────────────────────────────────────────────────┘
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Core Security Features
|
|
37
|
+
|
|
38
|
+
### 🛡️ Body Parsing Security
|
|
39
|
+
**Protection**: DoS attacks, prototype pollution, memory exhaustion
|
|
40
|
+
**Implementation**: Configurable size limits, depth validation, type checking
|
|
41
|
+
**Documentation**: [Body Parsing Security](./body-parsing.md)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
const secureApp = new YinzerFlow({
|
|
45
|
+
bodyParser: {
|
|
46
|
+
json: {
|
|
47
|
+
maxSize: 262144, // 256KB limit
|
|
48
|
+
maxDepth: 10, // Prevent stack overflow
|
|
49
|
+
allowPrototypeProperties: false, // Block prototype pollution
|
|
50
|
+
maxKeys: 1000 // Prevent memory exhaustion
|
|
51
|
+
},
|
|
52
|
+
fileUploads: {
|
|
53
|
+
maxFileSize: 10485760, // 10MB per file
|
|
54
|
+
blockedExtensions: ['.exe', '.bat', '.cmd'], // Block dangerous files
|
|
55
|
+
maxFiles: 10
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### 🛡️ CORS Security
|
|
62
|
+
**Protection**: Cross-origin attacks, unauthorized access
|
|
63
|
+
**Implementation**: Origin validation, header sanitization, preflight handling
|
|
64
|
+
**Documentation**: [CORS Security](./cors.md)
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
const secureApp = new YinzerFlow({
|
|
68
|
+
cors: {
|
|
69
|
+
enabled: true,
|
|
70
|
+
origin: ['https://yourdomain.com'], // Specific origins only
|
|
71
|
+
credentials: true,
|
|
72
|
+
methods: ['GET', 'POST', 'PUT', 'DELETE'],
|
|
73
|
+
allowedHeaders: ['Content-Type', 'Authorization']
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### 🛡️ IP Security
|
|
79
|
+
**Protection**: IP spoofing, load balancer bypass
|
|
80
|
+
**Implementation**: Trusted proxy validation, chain length limits
|
|
81
|
+
**Documentation**: [IP Security](./ip-security.md)
|
|
82
|
+
|
|
83
|
+
```typescript
|
|
84
|
+
const secureApp = new YinzerFlow({
|
|
85
|
+
ipSecurity: {
|
|
86
|
+
trustedProxies: ['127.0.0.1', '192.168.1.10'],
|
|
87
|
+
allowPrivateIps: true,
|
|
88
|
+
headerPreference: ['x-forwarded-for', 'x-real-ip'],
|
|
89
|
+
maxChainLength: 10,
|
|
90
|
+
detectSpoofing: true
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 🛡️ Route Security
|
|
96
|
+
**Protection**: Path traversal, parameter injection, method confusion
|
|
97
|
+
**Implementation**: Parameter validation, path normalization, method validation
|
|
98
|
+
**Documentation**: [Route Security](../core/routes.md#security-considerations)
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Automatic protection against:
|
|
102
|
+
// - Path traversal: /api/../etc/passwd
|
|
103
|
+
// - Parameter injection: /api/users/'; DROP TABLE users; --
|
|
104
|
+
// - Method confusion: Invalid HTTP methods
|
|
105
|
+
app.get('/api/users/:id', ({ request }) => {
|
|
106
|
+
const userId = request.params.id; // Automatically validated
|
|
107
|
+
return { userId };
|
|
108
|
+
});
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
### 🛡️ Error Handling Security
|
|
112
|
+
**Protection**: Information leakage, error-based attacks
|
|
113
|
+
**Implementation**: Safe error responses, no stack traces in production
|
|
114
|
+
**Documentation**: [Error Handling Security](../core/error-handling.md)
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// Global error handler prevents information leakage
|
|
118
|
+
app.onError(({ response }, error) => {
|
|
119
|
+
response.setStatusCode(500);
|
|
120
|
+
return { error: 'Internal server error' }; // No sensitive details
|
|
121
|
+
});
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 🛡️ Logging Security
|
|
125
|
+
**Protection**: Log injection, sensitive data exposure
|
|
126
|
+
**Implementation**: Structured logging, sensitive data filtering
|
|
127
|
+
**Documentation**: [Logging Security](./logging.md)
|
|
128
|
+
|
|
129
|
+
```typescript
|
|
130
|
+
const secureApp = new YinzerFlow({
|
|
131
|
+
logger: {
|
|
132
|
+
level: 'info',
|
|
133
|
+
sensitiveFields: ['password', 'token', 'secret'],
|
|
134
|
+
maskPatterns: [/credit_card_\d+/, /ssn_\d+/]
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Security Configuration Patterns
|
|
140
|
+
|
|
141
|
+
For detailed configuration examples and patterns, see [Configuration Patterns](../configuration/configuration-patterns.md).
|
|
142
|
+
|
|
143
|
+
### Security-First Configuration Principles
|
|
144
|
+
|
|
145
|
+
1. **Principle of Least Privilege**
|
|
146
|
+
- Configure only the features you need
|
|
147
|
+
- Use specific origins instead of wildcards
|
|
148
|
+
- Limit file upload types and sizes
|
|
149
|
+
- Restrict HTTP methods to those you use
|
|
150
|
+
|
|
151
|
+
2. **Defense in Depth**
|
|
152
|
+
- Combine multiple security layers
|
|
153
|
+
- Validate at both framework and application levels
|
|
154
|
+
- Use hooks for additional validation
|
|
155
|
+
- Implement custom security checks
|
|
156
|
+
|
|
157
|
+
3. **Secure by Default**
|
|
158
|
+
- YinzerFlow's defaults are secure
|
|
159
|
+
- Explicitly configure only when needed
|
|
160
|
+
- Test security configurations thoroughly
|
|
161
|
+
- Monitor for security events
|
|
162
|
+
|
|
163
|
+
4. **Regular Security Updates**
|
|
164
|
+
- Keep YinzerFlow updated
|
|
165
|
+
- Monitor security advisories
|
|
166
|
+
- Review and update configurations
|
|
167
|
+
- Test security features regularly
|
|
168
|
+
|
|
169
|
+
## Security Best Practices
|
|
170
|
+
|
|
171
|
+
For detailed security configuration examples and best practices, see [Configuration Patterns](../configuration/configuration-patterns.md).
|
|
172
|
+
|
|
173
|
+
### Key Security Principles
|
|
174
|
+
|
|
175
|
+
1. **Principle of Least Privilege** - Configure only what you need
|
|
176
|
+
2. **Defense in Depth** - Multiple security layers
|
|
177
|
+
3. **Secure by Default** - YinzerFlow's defaults are secure
|
|
178
|
+
4. **Regular Security Updates** - Keep configurations current
|
|
179
|
+
|
|
180
|
+
## Security Monitoring
|
|
181
|
+
|
|
182
|
+
### Built-in Security Logging
|
|
183
|
+
YinzerFlow automatically logs security events:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// Automatic logging of:
|
|
187
|
+
// - CORS violations
|
|
188
|
+
// - Body parsing errors
|
|
189
|
+
// - IP spoofing attempts
|
|
190
|
+
// - Route validation failures
|
|
191
|
+
// - Security configuration errors
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Custom Security Monitoring
|
|
195
|
+
Add custom security monitoring with hooks:
|
|
196
|
+
|
|
197
|
+
```typescript
|
|
198
|
+
app.beforeAll([
|
|
199
|
+
({ request, response }) => {
|
|
200
|
+
// Monitor for suspicious patterns
|
|
201
|
+
const suspiciousPatterns = [
|
|
202
|
+
/\.\.\//, // Path traversal
|
|
203
|
+
/<script>/i, // XSS attempts
|
|
204
|
+
/union\s+select/i, // SQL injection
|
|
205
|
+
/javascript:/i // Protocol injection
|
|
206
|
+
];
|
|
207
|
+
|
|
208
|
+
const url = request.url;
|
|
209
|
+
const body = JSON.stringify(request.body);
|
|
210
|
+
|
|
211
|
+
for (const pattern of suspiciousPatterns) {
|
|
212
|
+
if (pattern.test(url) || pattern.test(body)) {
|
|
213
|
+
console.warn('🚨 Suspicious request detected:', {
|
|
214
|
+
ip: request.ipAddress,
|
|
215
|
+
url: request.url,
|
|
216
|
+
pattern: pattern.source
|
|
217
|
+
});
|
|
218
|
+
response.setStatusCode(400);
|
|
219
|
+
return { error: 'Invalid request' };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
]);
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
## Security Testing
|
|
227
|
+
|
|
228
|
+
### Automated Security Testing
|
|
229
|
+
Test your security configuration:
|
|
230
|
+
|
|
231
|
+
```typescript
|
|
232
|
+
// Test body parsing limits
|
|
233
|
+
const testBodyLimits = async () => {
|
|
234
|
+
const response = await fetch('http://localhost:3000/api/test', {
|
|
235
|
+
method: 'POST',
|
|
236
|
+
headers: { 'Content-Type': 'application/json' },
|
|
237
|
+
body: JSON.stringify({ data: 'x'.repeat(300000) }) // Exceeds 256KB limit
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
console.assert(response.status === 413, 'Body size limit not enforced');
|
|
241
|
+
};
|
|
242
|
+
|
|
243
|
+
// Test CORS configuration
|
|
244
|
+
const testCORS = async () => {
|
|
245
|
+
const response = await fetch('http://localhost:3000/api/test', {
|
|
246
|
+
method: 'OPTIONS',
|
|
247
|
+
headers: { 'Origin': 'https://malicious.com' }
|
|
248
|
+
});
|
|
249
|
+
|
|
250
|
+
console.assert(response.status === 403, 'CORS origin validation not working');
|
|
251
|
+
};
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
## Security Checklist
|
|
255
|
+
|
|
256
|
+
Before deploying to production, verify:
|
|
257
|
+
|
|
258
|
+
- [ ] Body parsing limits configured appropriately
|
|
259
|
+
- [ ] CORS origins restricted to trusted domains
|
|
260
|
+
- [ ] IP security configured for your infrastructure
|
|
261
|
+
- [ ] File upload restrictions in place
|
|
262
|
+
- [ ] Error handling prevents information leakage
|
|
263
|
+
- [ ] Logging configured to avoid sensitive data exposure
|
|
264
|
+
- [ ] Security headers enabled
|
|
265
|
+
- [ ] HTTPS configured (if applicable)
|
|
266
|
+
- [ ] Security monitoring in place
|
|
267
|
+
- [ ] Regular security updates scheduled
|
|
268
|
+
|
|
269
|
+
## Getting Help
|
|
270
|
+
|
|
271
|
+
For detailed security documentation:
|
|
272
|
+
- **[Body Parsing](./body-parsing.md)** - File upload and JSON parsing security
|
|
273
|
+
- **[CORS](./cors.md)** - Cross-origin request security
|
|
274
|
+
- **[IP Security](./ip-security.md)** - Client IP validation and protection
|
|
275
|
+
- **[Logging](./logging.md)** - Secure logging practices
|
|
276
|
+
- **[Error Handling](../core/error-handling.md)** - Secure error handling patterns
|
|
277
|
+
|
|
278
|
+
For security issues or questions:
|
|
279
|
+
- Check the security documentation above
|
|
280
|
+
- Review the security configuration examples
|
|
281
|
+
- Test your security setup thoroughly
|
|
282
|
+
- Consider security implications of all custom code
|
package/docs/start-here.md
CHANGED
|
@@ -13,6 +13,8 @@ YinzerFlow is designed for developers who want:
|
|
|
13
13
|
|
|
14
14
|
## Quick Start
|
|
15
15
|
|
|
16
|
+
For a complete quick reference with all common patterns, see [Quick Reference](./quick-reference.md).
|
|
17
|
+
|
|
16
18
|
### Installation
|
|
17
19
|
|
|
18
20
|
```bash
|
|
@@ -106,17 +108,21 @@ For custom shutdown handling, see [Advanced Configuration](./advanced-configurat
|
|
|
106
108
|
|
|
107
109
|
### Core Features
|
|
108
110
|
|
|
109
|
-
- **[Routes](./routes.md)** - Comprehensive routing system with HTTP methods, parameters, hooks, and groups
|
|
110
|
-
- **[
|
|
111
|
-
- **[
|
|
112
|
-
- **[
|
|
111
|
+
- **[Routes](./core/routes.md)** - Comprehensive routing system with HTTP methods, parameters, hooks, and groups
|
|
112
|
+
- **[Context Object](./core/context.md)** - Central interface for request data, response controls, and request lifecycle
|
|
113
|
+
- **[Request Object](./core/request.md)** - Access headers, body, query parameters, route parameters, and raw body
|
|
114
|
+
- **[Response Object](./core/response.md)** - Set status codes, headers, and return various response types
|
|
115
|
+
- **[Error Handling](./core/error-handling.md)** - Automatic error catching, custom error handlers, and comprehensive error management
|
|
113
116
|
|
|
114
117
|
### Security & Configuration
|
|
115
118
|
|
|
116
|
-
- **[
|
|
117
|
-
- **[
|
|
118
|
-
- **[CORS](./cors.md)** - Cross-Origin Resource Sharing with comprehensive security measures
|
|
119
|
-
- **[
|
|
119
|
+
- **[Security Overview](./security/security-overview.md)** - Comprehensive security features and configuration patterns
|
|
120
|
+
- **[Body Parsing](./security/body-parsing.md)** - Secure parsing of JSON, file uploads, and form data with DoS protection
|
|
121
|
+
- **[CORS](./security/cors.md)** - Cross-Origin Resource Sharing with comprehensive security measures
|
|
122
|
+
- **[IP Security](./security/ip-security.md)** - Client IP validation and spoofing protection for load balancers and CDNs
|
|
123
|
+
- **[Logging](./security/logging.md)** - Flexible logging with custom logger support and Pittsburgh personality
|
|
124
|
+
- **[Configuration Patterns](./configuration/configuration-patterns.md)** - Common configuration patterns and best practices
|
|
125
|
+
- **[Advanced Configuration](./configuration/advanced-configuration-options.md)** - Fine-tune security, performance, and functionality
|
|
120
126
|
|
|
121
127
|
### Common Use Cases
|
|
122
128
|
|
package/example/app/index.ts
CHANGED
|
@@ -19,13 +19,13 @@ const app = new YinzerFlow({
|
|
|
19
19
|
|
|
20
20
|
|
|
21
21
|
|
|
22
|
-
app.onError((ctx) => {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
});
|
|
22
|
+
// app.onError((ctx) => {
|
|
23
|
+
// ctx.response.setStatusCode(500);
|
|
24
|
+
// return {
|
|
25
|
+
// success: false,
|
|
26
|
+
// message: "Something went wrong",
|
|
27
|
+
// };
|
|
28
|
+
// });
|
|
29
29
|
|
|
30
30
|
app.onNotFound((ctx) => {
|
|
31
31
|
ctx.response.setStatusCode(404);
|
package/index.d.ts
CHANGED
|
@@ -159,7 +159,7 @@ export interface Context<T extends InternalHandlerCallbackGenerics = InternalHan
|
|
|
159
159
|
* @param ctx - The request context containing request and response objects
|
|
160
160
|
* @returns A response body or a promise that resolves to a response body
|
|
161
161
|
*/
|
|
162
|
-
export type HandlerCallback<T extends InternalHandlerCallbackGenerics = InternalHandlerCallbackGenerics> = (ctx: Context<T
|
|
162
|
+
export type HandlerCallback<T extends InternalHandlerCallbackGenerics = InternalHandlerCallbackGenerics> = (ctx: Context<T>, error?: unknown) => Promise<T["response"] | void> | T["response"] | void;
|
|
163
163
|
export type InternalGlobalHookOptions = {
|
|
164
164
|
routesToExclude: Array<string>;
|
|
165
165
|
} & {
|
|
@@ -585,6 +585,7 @@ export interface InternalServerConfiguration {
|
|
|
585
585
|
*/
|
|
586
586
|
autoGracefulShutdown: boolean;
|
|
587
587
|
}
|
|
588
|
+
export type RouteGroup = Record<Lowercase<InternalHttpMethod>, InternalSetupMethod>;
|
|
588
589
|
export interface Setup {
|
|
589
590
|
get: InternalSetupMethod;
|
|
590
591
|
post: InternalSetupMethod;
|
|
@@ -592,7 +593,7 @@ export interface Setup {
|
|
|
592
593
|
patch: InternalSetupMethod;
|
|
593
594
|
delete: InternalSetupMethod;
|
|
594
595
|
options: InternalSetupMethod;
|
|
595
|
-
group: (prefix: string, callback: (group:
|
|
596
|
+
group: (prefix: string, callback: (group: RouteGroup) => void, options?: InternalRouteRegistryOptions) => void;
|
|
596
597
|
beforeAll: (handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions) => void;
|
|
597
598
|
afterAll: (handlers: Array<HandlerCallback>, options?: InternalGlobalHookOptions) => void;
|
|
598
599
|
onError: (handler: HandlerCallback) => void;
|
package/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var M1=Object.create;var{getPrototypeOf:U1,defineProperty:u$,getOwnPropertyNames:j1}=Object;var F1=Object.prototype.hasOwnProperty;var F$=($,W,Y)=>{Y=$!=null?M1(U1($)):{};let Z=W||!$||!$.__esModule?u$(Y,"default",{value:$,enumerable:!0}):Y;for(let D of j1($))if(!F1.call(Z,D))u$(Z,D,{get:()=>$[D],enumerable:!0});return Z};var _1=($,W)=>()=>(W||$((W={exports:{}}).exports,W),W.exports);var D$=_1((_$,V$)=>{(function($,W){typeof _$=="object"&&typeof V$!="undefined"?V$.exports=W():typeof define=="function"&&define.amd?define(W):($=typeof globalThis!="undefined"?globalThis:$||self).dayjs=W()})(_$,function(){var $=1000,W=60000,Y=3600000,Z="millisecond",D="second",Q="minute",X="hour",O="day",V="week",B="month",w="quarter",z="year",L="date",o="Invalid Date",M$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,e=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,U$={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(U){var G=["th","st","nd","rd"],J=U%100;return"["+U+(G[(J-20)%10]||G[J]||G[0])+"]"}},s=function(U,G,J){var M=String(U);return!M||M.length>=G?U:""+Array(G+1-M.length).join(J)+U},$$={s,z:function(U){var G=-U.utcOffset(),J=Math.abs(G),M=Math.floor(J/60),K=J%60;return(G<=0?"+":"-")+s(M,2,"0")+":"+s(K,2,"0")},m:function U(G,J){if(G.date()<J.date())return-U(J,G);var M=12*(J.year()-G.year())+(J.month()-G.month()),K=G.clone().add(M,B),j=J-K<0,F=G.clone().add(M+(j?-1:1),B);return+(-(M+(J-K)/(j?K-F:F-K))||0)},a:function(U){return U<0?Math.ceil(U)||0:Math.floor(U)},p:function(U){return{M:B,y:z,w:V,d:O,D:L,h:X,m:Q,s:D,ms:Z,Q:w}[U]||String(U||"").toLowerCase().replace(/s$/,"")},u:function(U){return U===void 0}},m="en",f={};f[m]=U$;var C$="$isDayjsObject",j$=function(U){return U instanceof Y$||!(!U||!U[C$])},W$=function U(G,J,M){var K;if(!G)return m;if(typeof G=="string"){var j=G.toLowerCase();f[j]&&(K=j),J&&(f[j]=J,K=j);var F=G.split("-");if(!K&&F.length>1)return U(F[0])}else{var q=G.name;f[q]=G,K=q}return!M&&K&&(m=K),K||!M&&m},S=function(U,G){if(j$(U))return U.clone();var J=typeof G=="object"?G:{};return J.date=U,J.args=arguments,new Y$(J)},H=$$;H.l=W$,H.i=j$,H.w=function(U,G){return S(U,{locale:G.$L,utc:G.$u,x:G.$x,$offset:G.$offset})};var Y$=function(){function U(J){this.$L=W$(J.locale,null,!0),this.parse(J),this.$x=this.$x||J.x||{},this[C$]=!0}var G=U.prototype;return G.parse=function(J){this.$d=function(M){var{date:K,utc:j}=M;if(K===null)return new Date(NaN);if(H.u(K))return new Date;if(K instanceof Date)return new Date(K);if(typeof K=="string"&&!/Z$/i.test(K)){var F=K.match(M$);if(F){var q=F[2]-1||0,E=(F[7]||"0").substring(0,3);return j?new Date(Date.UTC(F[1],q,F[3]||1,F[4]||0,F[5]||0,F[6]||0,E)):new Date(F[1],q,F[3]||1,F[4]||0,F[5]||0,F[6]||0,E)}}return new Date(K)}(J),this.init()},G.init=function(){var J=this.$d;this.$y=J.getFullYear(),this.$M=J.getMonth(),this.$D=J.getDate(),this.$W=J.getDay(),this.$H=J.getHours(),this.$m=J.getMinutes(),this.$s=J.getSeconds(),this.$ms=J.getMilliseconds()},G.$utils=function(){return H},G.isValid=function(){return this.$d.toString()!==o},G.isSame=function(J,M){var K=S(J);return this.startOf(M)<=K&&K<=this.endOf(M)},G.isAfter=function(J,M){return S(J)<this.startOf(M)},G.isBefore=function(J,M){return this.endOf(M)<S(J)},G.$g=function(J,M,K){return H.u(J)?this[M]:this.set(K,J)},G.unix=function(){return Math.floor(this.valueOf()/1000)},G.valueOf=function(){return this.$d.getTime()},G.startOf=function(J,M){var K=this,j=!!H.u(M)||M,F=H.p(J),q=function(l,T){var h=H.w(K.$u?Date.UTC(K.$y,T,l):new Date(K.$y,T,l),K);return j?h:h.endOf(O)},E=function(l,T){return H.w(K.toDate()[l].apply(K.toDate("s"),(j?[0,0,0,0]:[23,59,59,999]).slice(T)),K)},k=this.$W,I=this.$M,R=this.$D,c="set"+(this.$u?"UTC":"");switch(F){case z:return j?q(1,0):q(31,11);case B:return j?q(1,I):q(0,I+1);case V:var p=this.$locale().weekStart||0,a=(k<p?k+7:k)-p;return q(j?R-a:R+(6-a),I);case O:case L:return E(c+"Hours",0);case X:return E(c+"Minutes",1);case Q:return E(c+"Seconds",2);case D:return E(c+"Milliseconds",3);default:return this.clone()}},G.endOf=function(J){return this.startOf(J,!1)},G.$set=function(J,M){var K,j=H.p(J),F="set"+(this.$u?"UTC":""),q=(K={},K[O]=F+"Date",K[L]=F+"Date",K[B]=F+"Month",K[z]=F+"FullYear",K[X]=F+"Hours",K[Q]=F+"Minutes",K[D]=F+"Seconds",K[Z]=F+"Milliseconds",K)[j],E=j===O?this.$D+(M-this.$W):M;if(j===B||j===z){var k=this.clone().set(L,1);k.$d[q](E),k.init(),this.$d=k.set(L,Math.min(this.$D,k.daysInMonth())).$d}else q&&this.$d[q](E);return this.init(),this},G.set=function(J,M){return this.clone().$set(J,M)},G.get=function(J){return this[H.p(J)]()},G.add=function(J,M){var K,j=this;J=Number(J);var F=H.p(M),q=function(I){var R=S(j);return H.w(R.date(R.date()+Math.round(I*J)),j)};if(F===B)return this.set(B,this.$M+J);if(F===z)return this.set(z,this.$y+J);if(F===O)return q(1);if(F===V)return q(7);var E=(K={},K[Q]=W,K[X]=Y,K[D]=$,K)[F]||1,k=this.$d.getTime()+J*E;return H.w(k,this)},G.subtract=function(J,M){return this.add(-1*J,M)},G.format=function(J){var M=this,K=this.$locale();if(!this.isValid())return K.invalidDate||o;var j=J||"YYYY-MM-DDTHH:mm:ssZ",F=H.z(this),q=this.$H,E=this.$m,k=this.$M,I=K.weekdays,R=K.months,c=K.meridiem,p=function(T,h,n,Z$){return T&&(T[h]||T(M,j))||n[h].slice(0,Z$)},a=function(T){return H.s(q%12||12,T,"0")},l=c||function(T,h,n){var Z$=T<12?"AM":"PM";return n?Z$.toLowerCase():Z$};return j.replace(e,function(T,h){return h||function(n){switch(n){case"YY":return String(M.$y).slice(-2);case"YYYY":return H.s(M.$y,4,"0");case"M":return k+1;case"MM":return H.s(k+1,2,"0");case"MMM":return p(K.monthsShort,k,R,3);case"MMMM":return p(R,k);case"D":return M.$D;case"DD":return H.s(M.$D,2,"0");case"d":return String(M.$W);case"dd":return p(K.weekdaysMin,M.$W,I,2);case"ddd":return p(K.weekdaysShort,M.$W,I,3);case"dddd":return I[M.$W];case"H":return String(q);case"HH":return H.s(q,2,"0");case"h":return a(1);case"hh":return a(2);case"a":return l(q,E,!0);case"A":return l(q,E,!1);case"m":return String(E);case"mm":return H.s(E,2,"0");case"s":return String(M.$s);case"ss":return H.s(M.$s,2,"0");case"SSS":return H.s(M.$ms,3,"0");case"Z":return F}return null}(T)||F.replace(":","")})},G.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},G.diff=function(J,M,K){var j,F=this,q=H.p(M),E=S(J),k=(E.utcOffset()-this.utcOffset())*W,I=this-E,R=function(){return H.m(F,E)};switch(q){case z:j=R()/12;break;case B:j=R();break;case w:j=R()/3;break;case V:j=(I-k)/604800000;break;case O:j=(I-k)/86400000;break;case X:j=I/Y;break;case Q:j=I/W;break;case D:j=I/$;break;default:j=I}return K?j:H.a(j)},G.daysInMonth=function(){return this.endOf(B).$D},G.$locale=function(){return f[this.$L]},G.locale=function(J,M){if(!J)return this.$L;var K=this.clone(),j=W$(J,M,!0);return j&&(K.$L=j),K},G.clone=function(){return H.w(this.$d,this)},G.toDate=function(){return new Date(this.valueOf())},G.toJSON=function(){return this.isValid()?this.toISOString():null},G.toISOString=function(){return this.$d.toISOString()},G.toString=function(){return this.$d.toUTCString()},U}(),b$=Y$.prototype;return S.prototype=b$,[["$ms",Z],["$s",D],["$m",Q],["$H",X],["$W",O],["$M",B],["$y",z],["$D",L]].forEach(function(U){b$[U[1]]=function(G){return this.$g(G,U[0],U[1])}}),S.extend=function(U,G){return U.$i||(U(G,Y$,S),U.$i=!0),S},S.locale=W$,S.isDayjs=j$,S.unix=function(U){return S(1000*U)},S.en=f[m],S.Ls=f,S.p={},S})});import{createServer as p0}from"net";var w$=F$(D$(),1);var Q$={ok:"OK",created:"Created",accepted:"Accepted",noContent:"No Content",movedPermanently:"Moved Permanently",found:"Found",notModified:"Not Modified",badRequest:"Bad Request",unauthorized:"Unauthorized",forbidden:"Forbidden",notFound:"Not Found",methodNotAllowed:"Method Not Allowed",conflict:"Conflict",unsupportedMediaType:"Unsupported Media Type",tooManyRequests:"Too Many Requests",internalServerError:"Internal Server Error"},b={ok:200,created:201,accepted:202,noContent:204,movedPermanently:301,found:302,notModified:304,badRequest:400,unauthorized:401,forbidden:403,notFound:404,methodNotAllowed:405,conflict:409,unsupportedMediaType:415,tooManyRequests:429,internalServerError:500},A={delete:"DELETE",get:"GET",head:"HEAD",post:"POST",put:"PUT",patch:"PATCH",options:"OPTIONS"},v={json:"application/json",html:"text/html",form:"application/x-www-form-urlencoded",multipart:"multipart/form-data",xml:"application/xml",text:"text/plain",csv:"text/csv",yamlApplication:"application/yaml",yamlText:"text/yaml",urlEncodedJson:"application/x-www-form-urlencoded+json"},u={authorization:"Authorization",proxyAuthorization:"Proxy-Authorization",wwwAuthenticate:"WWW-Authenticate",cacheControl:"Cache-Control",etag:"ETag",expires:"Expires",lastModified:"Last-Modified",ifMatch:"If-Match",ifNoneMatch:"If-None-Match",ifModifiedSince:"If-Modified-Since",ifUnmodifiedSince:"If-Unmodified-Since",ifRange:"If-Range",age:"Age",vary:"Vary",contentType:"Content-Type",contentLength:"Content-Length",contentEncoding:"Content-Encoding",contentLanguage:"Content-Language",contentDisposition:"Content-Disposition",contentLocation:"Content-Location",contentRange:"Content-Range",accessControlAllowCredentials:"Access-Control-Allow-Credentials",accessControlAllowHeaders:"Access-Control-Allow-Headers",accessControlAllowMethods:"Access-Control-Allow-Methods",accessControlAllowOrigin:"Access-Control-Allow-Origin",accessControlExposeHeaders:"Access-Control-Expose-Headers",accessControlMaxAge:"Access-Control-Max-Age",accessControlRequestHeaders:"Access-Control-Request-Headers",accessControlRequestMethod:"Access-Control-Request-Method",accept:"Accept",acceptEncoding:"Accept-Encoding",acceptLanguage:"Accept-Language",acceptRanges:"Accept-Ranges",host:"Host",userAgent:"User-Agent",referer:"Referer",origin:"Origin",from:"From",expect:"Expect",location:"Location",server:"Server",date:"Date",allow:"Allow",retryAfter:"Retry-After",range:"Range",contentSecurityPolicy:"Content-Security-Policy",contentSecurityPolicyReportOnly:"Content-Security-Policy-Report-Only",strictTransportSecurity:"Strict-Transport-Security",xContentTypeOptions:"X-Content-Type-Options",xFrameOptions:"X-Frame-Options",xXSSProtection:"X-XSS-Protection",referrerPolicy:"Referrer-Policy",permissionsPolicy:"Permissions-Policy",crossOriginEmbedderPolicy:"Cross-Origin-Embedder-Policy",crossOriginOpenerPolicy:"Cross-Origin-Opener-Policy",crossOriginResourcePolicy:"Cross-Origin-Resource-Policy",cookie:"Cookie",setCookie:"Set-Cookie",connection:"Connection",keepAlive:"Keep-Alive",upgrade:"Upgrade",upgradeInsecureRequests:"Upgrade-Insecure-Requests",transferEncoding:"Transfer-Encoding",te:"TE",trailer:"Trailer",forwarded:"Forwarded",xForwardedFor:"X-Forwarded-For",via:"Via",maxForwards:"Max-Forwards",altSvc:"Alt-Svc",altUsed:"Alt-Used",timingAllowOrigin:"Timing-Allow-Origin",serverTiming:"Server-Timing",refresh:"Refresh",link:"Link",xPoweredBy:"X-Powered-By",xPermittedCrossDomainPolicies:"X-Permitted-Cross-Domain-Policies",reportTo:"Report-To",serviceWorkerAllowed:"Service-Worker-Allowed",sourceMap:"SourceMap",priority:"Priority",secGPC:"Sec-GPC",clearSiteData:"Clear-Site-Data",noVarySearch:"No-Vary-Search"},r={base64:"base64",binary:"binary",utf8:"utf8"};var X$=($,W)=>{if(!W.enabled)return!1;if($.request.method==="OPTIONS"){if(!h$($,W))return $.response.setStatusCode(403),$._response._setBody({error:"CORS: Origin not allowed",origin:$.request.headers.origin}),!0;$.response.setStatusCode(W.optionsSuccessStatus);let D=y$($,W);if($._response._setHeadersIfNotSet({[u.accessControlAllowOrigin]:D,[u.accessControlAllowMethods]:W.methods.join(", "),[u.accessControlAllowHeaders]:typeof W.allowedHeaders==="string"?W.allowedHeaders:W.allowedHeaders.join(", "),[u.accessControlAllowCredentials]:W.credentials?"true":"false",[u.accessControlExposeHeaders]:W.exposedHeaders.join(", "),[u.accessControlMaxAge]:W.maxAge.toString()}),W.preflightContinue)return!1;return $._response._setBody(""),!0}if(h$($,W)){let Z=y$($,W);$._response._setHeadersIfNotSet({[u.accessControlAllowOrigin]:Z,[u.accessControlAllowCredentials]:W.credentials?"true":"false"})}return!1},y$=($,W)=>{if(W.origin==="*"){if(W.credentials)throw new Error('CORS Security Error: origin: "*" with credentials: true is forbidden by CORS spec and creates security vulnerabilities. Use specific origins instead.');return"*"}let Y=$.request.headers.origin;if(Y)return Y;if(typeof W.origin==="string")return W.origin;if(Array.isArray(W.origin)&&W.origin.length>0){let[Z]=W.origin;return Z??"null"}return"null"},h$=($,W)=>{if(W.origin==="*")return!0;let Y=$.request.headers.origin?.toLowerCase()??"";if(typeof W.origin==="function")return Boolean(W.origin(Y,$.request));if(typeof W.origin==="string")return Y===W.origin.toLowerCase();if(Array.isArray(W.origin))return W.origin.some((Z)=>Y===Z.toLowerCase());if(W.origin instanceof RegExp)return W.origin.test(Y);return!1};var m$=F$(D$(),1),y="YINZER",N={reset:"\x1B[0m",cyan:"\x1B[96m",yellow:"\x1B[93m",red:"\x1B[91m",green:"\x1B[92m",magenta:"\x1B[95m",gray:"\x1B[90m"},V1={positive:["n'at!","yinz are good!","that's the way!","right on!","lookin' good!","way to go!","keep it up!"],neutral:["n'at","yinz know","just sayin'","that's how it is","what can ya do","it happens"],negative:["aw jeez","that ain't right","what a jagoff move","that's terrible n'at","somebody messed up","this is bad news","yinz better fix this"]},d=!1,P=null,C=()=>m$.default().format("YYYY-MM-DD HH:mm:ss.SSS"),H$=($)=>{let W=V1[$];return W[Math.floor(Math.random()*W.length)]??""},H1=($)=>{if(typeof $==="string")return Buffer.byteLength($,"utf8");if(Buffer.isBuffer($))return $.length;if(typeof $==="object"&&$!==null)try{return Buffer.byteLength(JSON.stringify($),"utf8")}catch{return 0}return 0},q1=($)=>{if($>=200&&$<300)return"✅";if($>=300&&$<400)return"\uD83D\uDD04";if($>=400&&$<500)return"❌";if($>=500)return"\uD83D\uDCA5";return"❓"},w1=($)=>{if($<50)return{emoji:"⚡",phrase:Math.random()<0.5?"lightning quick n'at!":"faster than a Stillers touchdown!"};if($<100)return{emoji:"\uD83D\uDD25",phrase:Math.random()<0.5?"that's the way!":"smooth as butter n'at!"};if($<200)return{emoji:"✅",phrase:Math.random()<0.5?"not bad yinz!":"keepin' up just fine!"};if($<500)return{emoji:"⚠️",phrase:Math.random()<0.5?"eh, could be better":"slowin' down a bit there"};if($<1000)return{emoji:"\uD83D\uDC0C",phrase:Math.random()<0.5?"that's draggin' n'at":"c'mon, pick up the pace!"};return{emoji:"\uD83D\uDCA5",phrase:Math.random()<0.5?"what a jagoff response time!":"slower than traffic on the Parkway!"}},N1=($,W,Y)=>{if(!d)return;let Z=C(),D=W??"unknown",Q=Y?` - ${Y}`:"",X="",O="info";if($==="connect")X=`\uD83E\uDD1D [NETWORK] New visitor from ${D} - Welcome to the 'Burgh!`;else if($==="disconnect")X=`\uD83D\uDC4B [NETWORK] ${D} headed out - Thanks for stopping by, yinz come back now!`;else X=`\uD83D\uDCA5 [NETWORK] Connection trouble with ${D}${Q} - That's not good, n'at!`,O="error";if(P)P[O](X);else{let V=O==="error"?N.red:N.gray;console.log(`${V}[${y}] [${Z}] ${X}${N.reset}`)}},B1=($,W,Y)=>{if(!d)return;let{request:Z}=$,D=$._response,Q=(Y-W).toFixed(1),X=Z.ipAddress||"unknown",{method:O,path:V,protocol:B}=Z,w=D._statusCode,z=H1(D._body),L=Z.headers.referer?`"${Z.headers.referer}"`:'"-"',o=Z.headers["user-agent"]?`"${Z.headers["user-agent"]}"`:'"-"',M$=q1(w),e=`\uD83C\uDFE0 ${X} - - [${C()}] "${O} ${V} ${B}" ${w} ${z}b ${L} ${o} ${Q}ms ${M$}`,U$=parseFloat(Q),{emoji:s,phrase:$$}=w1(U$),m=`${s} [PERF] Response time: ${Q}ms - ${$$}`;if(P)P.info(`[NETWORK] ${e}`),P.info(`[PERF] ${m}`);else console.log(`${N.gray}[${y}] [${C()}] [NETWORK] ${e}${N.reset}`),console.log(`${N.magenta}[${y}] ${s} [${C()}] [PERF] Response time: ${Q}ms - ${$$}${N.reset}`)},E1=($,W)=>{if(!d)return;let Y=C(),Z=$&&W?`${W}:${$}`:"unknown",D=H$("positive"),Q=`\uD83D\uDE80 [NETWORK] YinzerFlow server is up and running at ${Z} - Ready to serve yinz all, ${D}!`;if(P)P.info(Q);else console.log(`${N.gray}[${y}] [${Y}] ${Q}${N.reset}`)},A1=($,W)=>{if(!d)return;let Y=C(),Z=$&&W?`${W}:${$}`:"unknown",D=H$("neutral"),Q=`\uD83D\uDED1 [NETWORK] YinzerFlow server at ${Z} is shutting down - See yinz later, ${D}!`;if(P)P.info(Q);else console.log(`${N.gray}[${y}] [${Y}] ${Q}${N.reset}`)},z1=($,W,Y)=>{if(!d)return;let Z=C(),D=$&&W?`${W}:${$}`:"unknown",Q=Y?` - ${Y}`:"",X=H$("negative"),O=`\uD83D\uDCA5 [NETWORK] Server error at ${D}${Q} - Something's not right, ${X}!`;if(P)P.error(O);else console.log(`${N.red}[${y}] [${Z}] ${O}${N.reset}`)},S1=($)=>{d=$},k1=($)=>{P=$},x={setEnabled:S1,setNetworkLogger:k1,connection:N1,request:B1,serverStart:E1,serverStop:A1,serverError:z1};var i={off:0,error:1,warn:2,info:3},I1={positive:["n'at!","yinz are good!","that's the way!","right on!","lookin' good!","way to go!","keep it up!"],neutral:["n'at","yinz know","just sayin'","that's how it is","what can ya do","it happens"],negative:["aw jeez","that ain't right","what a jagoff move","that's terrible n'at","somebody messed up","this is bad news","yinz better fix this"]},t=i.warn,g=null,L1=($)=>{let W=I1[$];return W[Math.floor(Math.random()*W.length)]??""},T1=(...$)=>{if(t<i.info)return;if(g)g.info(...$);else q$("info",...$)},R1=(...$)=>{if(t<i.warn)return;if(g)g.warn(...$);else q$("warn",...$)},v1=(...$)=>{if(t<i.error)return;if(g)g.error(...$);else q$("error",...$)},P1=($,W,Y)=>{if(t<i.info)return;let Z=C(),D="❓ ",Q="";if(W<50)D="⚡ ",Q=Math.random()<0.5?"lightning quick n'at!":"faster than a Stillers touchdown!";else if(W<100)D="\uD83D\uDD25 ",Q=Math.random()<0.5?"that's the way!":"smooth as butter n'at!";else if(W<200)D="✅ ",Q=Math.random()<0.5?"not bad yinz!":"keepin' up just fine!";else if(W<500)D="⚠️ ",Q=Math.random()<0.5?"eh, could be better":"slowin' down a bit there";else if(W<1000)D="\uD83D\uDC0C ",Q=Math.random()<0.5?"that's draggin' n'at":"c'mon, pick up the pace!";else D="\uD83D\uDCA5 ",Q=Math.random()<0.5?"what a jagoff response time!":"slower than traffic on the Parkway!";let X=`${N.magenta}[${y}] ${D} [${Z}] [PERF]${N.reset}`,O=Y?{...Y,executionTime:`${W}ms`}:{executionTime:`${W}ms`};console.log(`${X} ${$} -`,O,`- ${Q}`)},x1=($)=>{t={off:0,error:1,warn:2,info:3}[$]},C1=($)=>{g=$},q$=($,...W)=>{let Y=C(),Z="✅ ",D=N.cyan,Q="positive",X="log";if($==="error")Z="❌ ",D=N.red,Q="negative",X="error";else if($==="warn")Z="⚠️ ",D=N.yellow,Q="neutral",X="warn";else Z="✅ ",D=N.cyan,Q="positive",X="log";let O=L1(Q),V=`${D}[${y}] ${Z}[${Y}] [${$.toUpperCase()}]${N.reset}`;console[X](`${V}`,...W,`- ${O}`)},_={setLogLevel:x1,setCustomLogger:C1,info:T1,warn:R1,error:v1,perf:P1,levels:i};class N${setup;constructor($){this.setup=$}async handle($){try{if(X$($,this.setup._configuration.cors)){$._response._parseResponseIntoString();return}let Y=this.setup._routeRegistry._findRoute($.request.method,$.request.path);if(!Y){let w=await this.setup._hooks._onNotFound($);$._response._setBody(w),$._response._parseResponseIntoString();return}$.request.params=Y.params;let{handler:Z,options:D}=Y,{beforeHooks:Q,afterHooks:X}=D,O=this.setup._hooks._beforeAll;for(let w of O)await w.handler($);for(let w of Q)await w($);let V=null;try{V=await Z($)}catch(w){throw w}for(let w of X)await w($);let B=this.setup._hooks._afterAll;for(let w of B)await w.handler($);if($._response._setBody(V),$.request.method==="HEAD")$._response._setBody(null);$._response._parseResponseIntoString();return}catch(W){await this.handleError($,W)}}async handleError($,W){try{_.error("Error in request handler",W);let Y=this.setup._hooks._onError,Z=await Y($);$._response._setBody(Z),X$($,this.setup._configuration.cors),$._response._parseResponseIntoString(),$._response._setHeadersIfNotSet({Date:w$.default().format("ddd, DD MMM YYYY HH:mm:ss [GMT]"),"Content-Length":$._response._stringBody.split(`
|
|
1
|
+
var M1=Object.create;var{getPrototypeOf:U1,defineProperty:u$,getOwnPropertyNames:j1}=Object;var F1=Object.prototype.hasOwnProperty;var F$=($,W,Y)=>{Y=$!=null?M1(U1($)):{};let Z=W||!$||!$.__esModule?u$(Y,"default",{value:$,enumerable:!0}):Y;for(let D of j1($))if(!F1.call(Z,D))u$(Z,D,{get:()=>$[D],enumerable:!0});return Z};var _1=($,W)=>()=>(W||$((W={exports:{}}).exports,W),W.exports);var D$=_1((_$,V$)=>{(function($,W){typeof _$=="object"&&typeof V$!="undefined"?V$.exports=W():typeof define=="function"&&define.amd?define(W):($=typeof globalThis!="undefined"?globalThis:$||self).dayjs=W()})(_$,function(){var $=1000,W=60000,Y=3600000,Z="millisecond",D="second",Q="minute",X="hour",O="day",V="week",B="month",w="quarter",z="year",L="date",o="Invalid Date",M$=/^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/,e=/\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g,U$={name:"en",weekdays:"Sunday_Monday_Tuesday_Wednesday_Thursday_Friday_Saturday".split("_"),months:"January_February_March_April_May_June_July_August_September_October_November_December".split("_"),ordinal:function(U){var G=["th","st","nd","rd"],J=U%100;return"["+U+(G[(J-20)%10]||G[J]||G[0])+"]"}},s=function(U,G,J){var M=String(U);return!M||M.length>=G?U:""+Array(G+1-M.length).join(J)+U},$$={s,z:function(U){var G=-U.utcOffset(),J=Math.abs(G),M=Math.floor(J/60),K=J%60;return(G<=0?"+":"-")+s(M,2,"0")+":"+s(K,2,"0")},m:function U(G,J){if(G.date()<J.date())return-U(J,G);var M=12*(J.year()-G.year())+(J.month()-G.month()),K=G.clone().add(M,B),j=J-K<0,F=G.clone().add(M+(j?-1:1),B);return+(-(M+(J-K)/(j?K-F:F-K))||0)},a:function(U){return U<0?Math.ceil(U)||0:Math.floor(U)},p:function(U){return{M:B,y:z,w:V,d:O,D:L,h:X,m:Q,s:D,ms:Z,Q:w}[U]||String(U||"").toLowerCase().replace(/s$/,"")},u:function(U){return U===void 0}},m="en",f={};f[m]=U$;var C$="$isDayjsObject",j$=function(U){return U instanceof Y$||!(!U||!U[C$])},W$=function U(G,J,M){var K;if(!G)return m;if(typeof G=="string"){var j=G.toLowerCase();f[j]&&(K=j),J&&(f[j]=J,K=j);var F=G.split("-");if(!K&&F.length>1)return U(F[0])}else{var q=G.name;f[q]=G,K=q}return!M&&K&&(m=K),K||!M&&m},S=function(U,G){if(j$(U))return U.clone();var J=typeof G=="object"?G:{};return J.date=U,J.args=arguments,new Y$(J)},H=$$;H.l=W$,H.i=j$,H.w=function(U,G){return S(U,{locale:G.$L,utc:G.$u,x:G.$x,$offset:G.$offset})};var Y$=function(){function U(J){this.$L=W$(J.locale,null,!0),this.parse(J),this.$x=this.$x||J.x||{},this[C$]=!0}var G=U.prototype;return G.parse=function(J){this.$d=function(M){var{date:K,utc:j}=M;if(K===null)return new Date(NaN);if(H.u(K))return new Date;if(K instanceof Date)return new Date(K);if(typeof K=="string"&&!/Z$/i.test(K)){var F=K.match(M$);if(F){var q=F[2]-1||0,E=(F[7]||"0").substring(0,3);return j?new Date(Date.UTC(F[1],q,F[3]||1,F[4]||0,F[5]||0,F[6]||0,E)):new Date(F[1],q,F[3]||1,F[4]||0,F[5]||0,F[6]||0,E)}}return new Date(K)}(J),this.init()},G.init=function(){var J=this.$d;this.$y=J.getFullYear(),this.$M=J.getMonth(),this.$D=J.getDate(),this.$W=J.getDay(),this.$H=J.getHours(),this.$m=J.getMinutes(),this.$s=J.getSeconds(),this.$ms=J.getMilliseconds()},G.$utils=function(){return H},G.isValid=function(){return this.$d.toString()!==o},G.isSame=function(J,M){var K=S(J);return this.startOf(M)<=K&&K<=this.endOf(M)},G.isAfter=function(J,M){return S(J)<this.startOf(M)},G.isBefore=function(J,M){return this.endOf(M)<S(J)},G.$g=function(J,M,K){return H.u(J)?this[M]:this.set(K,J)},G.unix=function(){return Math.floor(this.valueOf()/1000)},G.valueOf=function(){return this.$d.getTime()},G.startOf=function(J,M){var K=this,j=!!H.u(M)||M,F=H.p(J),q=function(l,T){var h=H.w(K.$u?Date.UTC(K.$y,T,l):new Date(K.$y,T,l),K);return j?h:h.endOf(O)},E=function(l,T){return H.w(K.toDate()[l].apply(K.toDate("s"),(j?[0,0,0,0]:[23,59,59,999]).slice(T)),K)},k=this.$W,I=this.$M,R=this.$D,c="set"+(this.$u?"UTC":"");switch(F){case z:return j?q(1,0):q(31,11);case B:return j?q(1,I):q(0,I+1);case V:var p=this.$locale().weekStart||0,a=(k<p?k+7:k)-p;return q(j?R-a:R+(6-a),I);case O:case L:return E(c+"Hours",0);case X:return E(c+"Minutes",1);case Q:return E(c+"Seconds",2);case D:return E(c+"Milliseconds",3);default:return this.clone()}},G.endOf=function(J){return this.startOf(J,!1)},G.$set=function(J,M){var K,j=H.p(J),F="set"+(this.$u?"UTC":""),q=(K={},K[O]=F+"Date",K[L]=F+"Date",K[B]=F+"Month",K[z]=F+"FullYear",K[X]=F+"Hours",K[Q]=F+"Minutes",K[D]=F+"Seconds",K[Z]=F+"Milliseconds",K)[j],E=j===O?this.$D+(M-this.$W):M;if(j===B||j===z){var k=this.clone().set(L,1);k.$d[q](E),k.init(),this.$d=k.set(L,Math.min(this.$D,k.daysInMonth())).$d}else q&&this.$d[q](E);return this.init(),this},G.set=function(J,M){return this.clone().$set(J,M)},G.get=function(J){return this[H.p(J)]()},G.add=function(J,M){var K,j=this;J=Number(J);var F=H.p(M),q=function(I){var R=S(j);return H.w(R.date(R.date()+Math.round(I*J)),j)};if(F===B)return this.set(B,this.$M+J);if(F===z)return this.set(z,this.$y+J);if(F===O)return q(1);if(F===V)return q(7);var E=(K={},K[Q]=W,K[X]=Y,K[D]=$,K)[F]||1,k=this.$d.getTime()+J*E;return H.w(k,this)},G.subtract=function(J,M){return this.add(-1*J,M)},G.format=function(J){var M=this,K=this.$locale();if(!this.isValid())return K.invalidDate||o;var j=J||"YYYY-MM-DDTHH:mm:ssZ",F=H.z(this),q=this.$H,E=this.$m,k=this.$M,I=K.weekdays,R=K.months,c=K.meridiem,p=function(T,h,n,Z$){return T&&(T[h]||T(M,j))||n[h].slice(0,Z$)},a=function(T){return H.s(q%12||12,T,"0")},l=c||function(T,h,n){var Z$=T<12?"AM":"PM";return n?Z$.toLowerCase():Z$};return j.replace(e,function(T,h){return h||function(n){switch(n){case"YY":return String(M.$y).slice(-2);case"YYYY":return H.s(M.$y,4,"0");case"M":return k+1;case"MM":return H.s(k+1,2,"0");case"MMM":return p(K.monthsShort,k,R,3);case"MMMM":return p(R,k);case"D":return M.$D;case"DD":return H.s(M.$D,2,"0");case"d":return String(M.$W);case"dd":return p(K.weekdaysMin,M.$W,I,2);case"ddd":return p(K.weekdaysShort,M.$W,I,3);case"dddd":return I[M.$W];case"H":return String(q);case"HH":return H.s(q,2,"0");case"h":return a(1);case"hh":return a(2);case"a":return l(q,E,!0);case"A":return l(q,E,!1);case"m":return String(E);case"mm":return H.s(E,2,"0");case"s":return String(M.$s);case"ss":return H.s(M.$s,2,"0");case"SSS":return H.s(M.$ms,3,"0");case"Z":return F}return null}(T)||F.replace(":","")})},G.utcOffset=function(){return 15*-Math.round(this.$d.getTimezoneOffset()/15)},G.diff=function(J,M,K){var j,F=this,q=H.p(M),E=S(J),k=(E.utcOffset()-this.utcOffset())*W,I=this-E,R=function(){return H.m(F,E)};switch(q){case z:j=R()/12;break;case B:j=R();break;case w:j=R()/3;break;case V:j=(I-k)/604800000;break;case O:j=(I-k)/86400000;break;case X:j=I/Y;break;case Q:j=I/W;break;case D:j=I/$;break;default:j=I}return K?j:H.a(j)},G.daysInMonth=function(){return this.endOf(B).$D},G.$locale=function(){return f[this.$L]},G.locale=function(J,M){if(!J)return this.$L;var K=this.clone(),j=W$(J,M,!0);return j&&(K.$L=j),K},G.clone=function(){return H.w(this.$d,this)},G.toDate=function(){return new Date(this.valueOf())},G.toJSON=function(){return this.isValid()?this.toISOString():null},G.toISOString=function(){return this.$d.toISOString()},G.toString=function(){return this.$d.toUTCString()},U}(),b$=Y$.prototype;return S.prototype=b$,[["$ms",Z],["$s",D],["$m",Q],["$H",X],["$W",O],["$M",B],["$y",z],["$D",L]].forEach(function(U){b$[U[1]]=function(G){return this.$g(G,U[0],U[1])}}),S.extend=function(U,G){return U.$i||(U(G,Y$,S),U.$i=!0),S},S.locale=W$,S.isDayjs=j$,S.unix=function(U){return S(1000*U)},S.en=f[m],S.Ls=f,S.p={},S})});import{createServer as p0}from"net";var w$=F$(D$(),1);var Q$={ok:"OK",created:"Created",accepted:"Accepted",noContent:"No Content",movedPermanently:"Moved Permanently",found:"Found",notModified:"Not Modified",badRequest:"Bad Request",unauthorized:"Unauthorized",forbidden:"Forbidden",notFound:"Not Found",methodNotAllowed:"Method Not Allowed",conflict:"Conflict",unsupportedMediaType:"Unsupported Media Type",tooManyRequests:"Too Many Requests",internalServerError:"Internal Server Error"},b={ok:200,created:201,accepted:202,noContent:204,movedPermanently:301,found:302,notModified:304,badRequest:400,unauthorized:401,forbidden:403,notFound:404,methodNotAllowed:405,conflict:409,unsupportedMediaType:415,tooManyRequests:429,internalServerError:500},A={delete:"DELETE",get:"GET",head:"HEAD",post:"POST",put:"PUT",patch:"PATCH",options:"OPTIONS"},v={json:"application/json",html:"text/html",form:"application/x-www-form-urlencoded",multipart:"multipart/form-data",xml:"application/xml",text:"text/plain",csv:"text/csv",yamlApplication:"application/yaml",yamlText:"text/yaml",urlEncodedJson:"application/x-www-form-urlencoded+json"},u={authorization:"Authorization",proxyAuthorization:"Proxy-Authorization",wwwAuthenticate:"WWW-Authenticate",cacheControl:"Cache-Control",etag:"ETag",expires:"Expires",lastModified:"Last-Modified",ifMatch:"If-Match",ifNoneMatch:"If-None-Match",ifModifiedSince:"If-Modified-Since",ifUnmodifiedSince:"If-Unmodified-Since",ifRange:"If-Range",age:"Age",vary:"Vary",contentType:"Content-Type",contentLength:"Content-Length",contentEncoding:"Content-Encoding",contentLanguage:"Content-Language",contentDisposition:"Content-Disposition",contentLocation:"Content-Location",contentRange:"Content-Range",accessControlAllowCredentials:"Access-Control-Allow-Credentials",accessControlAllowHeaders:"Access-Control-Allow-Headers",accessControlAllowMethods:"Access-Control-Allow-Methods",accessControlAllowOrigin:"Access-Control-Allow-Origin",accessControlExposeHeaders:"Access-Control-Expose-Headers",accessControlMaxAge:"Access-Control-Max-Age",accessControlRequestHeaders:"Access-Control-Request-Headers",accessControlRequestMethod:"Access-Control-Request-Method",accept:"Accept",acceptEncoding:"Accept-Encoding",acceptLanguage:"Accept-Language",acceptRanges:"Accept-Ranges",host:"Host",userAgent:"User-Agent",referer:"Referer",origin:"Origin",from:"From",expect:"Expect",location:"Location",server:"Server",date:"Date",allow:"Allow",retryAfter:"Retry-After",range:"Range",contentSecurityPolicy:"Content-Security-Policy",contentSecurityPolicyReportOnly:"Content-Security-Policy-Report-Only",strictTransportSecurity:"Strict-Transport-Security",xContentTypeOptions:"X-Content-Type-Options",xFrameOptions:"X-Frame-Options",xXSSProtection:"X-XSS-Protection",referrerPolicy:"Referrer-Policy",permissionsPolicy:"Permissions-Policy",crossOriginEmbedderPolicy:"Cross-Origin-Embedder-Policy",crossOriginOpenerPolicy:"Cross-Origin-Opener-Policy",crossOriginResourcePolicy:"Cross-Origin-Resource-Policy",cookie:"Cookie",setCookie:"Set-Cookie",connection:"Connection",keepAlive:"Keep-Alive",upgrade:"Upgrade",upgradeInsecureRequests:"Upgrade-Insecure-Requests",transferEncoding:"Transfer-Encoding",te:"TE",trailer:"Trailer",forwarded:"Forwarded",xForwardedFor:"X-Forwarded-For",via:"Via",maxForwards:"Max-Forwards",altSvc:"Alt-Svc",altUsed:"Alt-Used",timingAllowOrigin:"Timing-Allow-Origin",serverTiming:"Server-Timing",refresh:"Refresh",link:"Link",xPoweredBy:"X-Powered-By",xPermittedCrossDomainPolicies:"X-Permitted-Cross-Domain-Policies",reportTo:"Report-To",serviceWorkerAllowed:"Service-Worker-Allowed",sourceMap:"SourceMap",priority:"Priority",secGPC:"Sec-GPC",clearSiteData:"Clear-Site-Data",noVarySearch:"No-Vary-Search"},r={base64:"base64",binary:"binary",utf8:"utf8"};var X$=($,W)=>{if(!W.enabled)return!1;if($.request.method==="OPTIONS"){if(!h$($,W))return $.response.setStatusCode(403),$._response._setBody({error:"CORS: Origin not allowed",origin:$.request.headers.origin}),!0;$.response.setStatusCode(W.optionsSuccessStatus);let D=y$($,W);if($._response._setHeadersIfNotSet({[u.accessControlAllowOrigin]:D,[u.accessControlAllowMethods]:W.methods.join(", "),[u.accessControlAllowHeaders]:typeof W.allowedHeaders==="string"?W.allowedHeaders:W.allowedHeaders.join(", "),[u.accessControlAllowCredentials]:W.credentials?"true":"false",[u.accessControlExposeHeaders]:W.exposedHeaders.join(", "),[u.accessControlMaxAge]:W.maxAge.toString()}),W.preflightContinue)return!1;return $._response._setBody(""),!0}if(h$($,W)){let Z=y$($,W);$._response._setHeadersIfNotSet({[u.accessControlAllowOrigin]:Z,[u.accessControlAllowCredentials]:W.credentials?"true":"false"})}return!1},y$=($,W)=>{if(W.origin==="*"){if(W.credentials)throw new Error('CORS Security Error: origin: "*" with credentials: true is forbidden by CORS spec and creates security vulnerabilities. Use specific origins instead.');return"*"}let Y=$.request.headers.origin;if(Y)return Y;if(typeof W.origin==="string")return W.origin;if(Array.isArray(W.origin)&&W.origin.length>0){let[Z]=W.origin;return Z??"null"}return"null"},h$=($,W)=>{if(W.origin==="*")return!0;let Y=$.request.headers.origin?.toLowerCase()??"";if(typeof W.origin==="function")return Boolean(W.origin(Y,$.request));if(typeof W.origin==="string")return Y===W.origin.toLowerCase();if(Array.isArray(W.origin))return W.origin.some((Z)=>Y===Z.toLowerCase());if(W.origin instanceof RegExp)return W.origin.test(Y);return!1};var m$=F$(D$(),1),y="YINZER",N={reset:"\x1B[0m",cyan:"\x1B[96m",yellow:"\x1B[93m",red:"\x1B[91m",green:"\x1B[92m",magenta:"\x1B[95m",gray:"\x1B[90m"},V1={positive:["n'at!","yinz are good!","that's the way!","right on!","lookin' good!","way to go!","keep it up!"],neutral:["n'at","yinz know","just sayin'","that's how it is","what can ya do","it happens"],negative:["aw jeez","that ain't right","what a jagoff move","that's terrible n'at","somebody messed up","this is bad news","yinz better fix this"]},d=!1,P=null,C=()=>m$.default().format("YYYY-MM-DD HH:mm:ss.SSS"),H$=($)=>{let W=V1[$];return W[Math.floor(Math.random()*W.length)]??""},H1=($)=>{if(typeof $==="string")return Buffer.byteLength($,"utf8");if(Buffer.isBuffer($))return $.length;if(typeof $==="object"&&$!==null)try{return Buffer.byteLength(JSON.stringify($),"utf8")}catch{return 0}return 0},q1=($)=>{if($>=200&&$<300)return"✅";if($>=300&&$<400)return"\uD83D\uDD04";if($>=400&&$<500)return"❌";if($>=500)return"\uD83D\uDCA5";return"❓"},w1=($)=>{if($<50)return{emoji:"⚡",phrase:Math.random()<0.5?"lightning quick n'at!":"faster than a Stillers touchdown!"};if($<100)return{emoji:"\uD83D\uDD25",phrase:Math.random()<0.5?"that's the way!":"smooth as butter n'at!"};if($<200)return{emoji:"✅",phrase:Math.random()<0.5?"not bad yinz!":"keepin' up just fine!"};if($<500)return{emoji:"⚠️",phrase:Math.random()<0.5?"eh, could be better":"slowin' down a bit there"};if($<1000)return{emoji:"\uD83D\uDC0C",phrase:Math.random()<0.5?"that's draggin' n'at":"c'mon, pick up the pace!"};return{emoji:"\uD83D\uDCA5",phrase:Math.random()<0.5?"what a jagoff response time!":"slower than traffic on the Parkway!"}},N1=($,W,Y)=>{if(!d)return;let Z=C(),D=W??"unknown",Q=Y?` - ${Y}`:"",X="",O="info";if($==="connect")X=`\uD83E\uDD1D [NETWORK] New visitor from ${D} - Welcome to the 'Burgh!`;else if($==="disconnect")X=`\uD83D\uDC4B [NETWORK] ${D} headed out - Thanks for stopping by, yinz come back now!`;else X=`\uD83D\uDCA5 [NETWORK] Connection trouble with ${D}${Q} - That's not good, n'at!`,O="error";if(P)P[O](X);else{let V=O==="error"?N.red:N.gray;console.log(`${V}[${y}] [${Z}] ${X}${N.reset}`)}},B1=($,W,Y)=>{if(!d)return;let{request:Z}=$,D=$._response,Q=(Y-W).toFixed(1),X=Z.ipAddress||"unknown",{method:O,path:V,protocol:B}=Z,w=D._statusCode,z=H1(D._body),L=Z.headers.referer?`"${Z.headers.referer}"`:'"-"',o=Z.headers["user-agent"]?`"${Z.headers["user-agent"]}"`:'"-"',M$=q1(w),e=`\uD83C\uDFE0 ${X} - - [${C()}] "${O} ${V} ${B}" ${w} ${z}b ${L} ${o} ${Q}ms ${M$}`,U$=parseFloat(Q),{emoji:s,phrase:$$}=w1(U$),m=`${s} [PERF] Response time: ${Q}ms - ${$$}`;if(P)P.info(`[NETWORK] ${e}`),P.info(`[PERF] ${m}`);else console.log(`${N.gray}[${y}] [${C()}] [NETWORK] ${e}${N.reset}`),console.log(`${N.magenta}[${y}] ${s} [${C()}] [PERF] Response time: ${Q}ms - ${$$}${N.reset}`)},E1=($,W)=>{if(!d)return;let Y=C(),Z=$&&W?`${W}:${$}`:"unknown",D=H$("positive"),Q=`\uD83D\uDE80 [NETWORK] YinzerFlow server is up and running at ${Z} - Ready to serve yinz all, ${D}!`;if(P)P.info(Q);else console.log(`${N.gray}[${y}] [${Y}] ${Q}${N.reset}`)},A1=($,W)=>{if(!d)return;let Y=C(),Z=$&&W?`${W}:${$}`:"unknown",D=H$("neutral"),Q=`\uD83D\uDED1 [NETWORK] YinzerFlow server at ${Z} is shutting down - See yinz later, ${D}!`;if(P)P.info(Q);else console.log(`${N.gray}[${y}] [${Y}] ${Q}${N.reset}`)},z1=($,W,Y)=>{if(!d)return;let Z=C(),D=$&&W?`${W}:${$}`:"unknown",Q=Y?` - ${Y}`:"",X=H$("negative"),O=`\uD83D\uDCA5 [NETWORK] Server error at ${D}${Q} - Something's not right, ${X}!`;if(P)P.error(O);else console.log(`${N.red}[${y}] [${Z}] ${O}${N.reset}`)},S1=($)=>{d=$},k1=($)=>{P=$},x={setEnabled:S1,setNetworkLogger:k1,connection:N1,request:B1,serverStart:E1,serverStop:A1,serverError:z1};var i={off:0,error:1,warn:2,info:3},I1={positive:["n'at!","yinz are good!","that's the way!","right on!","lookin' good!","way to go!","keep it up!"],neutral:["n'at","yinz know","just sayin'","that's how it is","what can ya do","it happens"],negative:["aw jeez","that ain't right","what a jagoff move","that's terrible n'at","somebody messed up","this is bad news","yinz better fix this"]},t=i.warn,g=null,L1=($)=>{let W=I1[$];return W[Math.floor(Math.random()*W.length)]??""},T1=(...$)=>{if(t<i.info)return;if(g)g.info(...$);else q$("info",...$)},R1=(...$)=>{if(t<i.warn)return;if(g)g.warn(...$);else q$("warn",...$)},v1=(...$)=>{if(t<i.error)return;if(g)g.error(...$);else q$("error",...$)},P1=($,W,Y)=>{if(t<i.info)return;let Z=C(),D="❓ ",Q="";if(W<50)D="⚡ ",Q=Math.random()<0.5?"lightning quick n'at!":"faster than a Stillers touchdown!";else if(W<100)D="\uD83D\uDD25 ",Q=Math.random()<0.5?"that's the way!":"smooth as butter n'at!";else if(W<200)D="✅ ",Q=Math.random()<0.5?"not bad yinz!":"keepin' up just fine!";else if(W<500)D="⚠️ ",Q=Math.random()<0.5?"eh, could be better":"slowin' down a bit there";else if(W<1000)D="\uD83D\uDC0C ",Q=Math.random()<0.5?"that's draggin' n'at":"c'mon, pick up the pace!";else D="\uD83D\uDCA5 ",Q=Math.random()<0.5?"what a jagoff response time!":"slower than traffic on the Parkway!";let X=`${N.magenta}[${y}] ${D} [${Z}] [PERF]${N.reset}`,O=Y?{...Y,executionTime:`${W}ms`}:{executionTime:`${W}ms`};console.log(`${X} ${$} -`,O,`- ${Q}`)},x1=($)=>{t={off:0,error:1,warn:2,info:3}[$]},C1=($)=>{g=$},q$=($,...W)=>{let Y=C(),Z="✅ ",D=N.cyan,Q="positive",X="info";if($==="error")Z="❌ ",D=N.red,Q="negative",X="error";else if($==="warn")Z="⚠️ ",D=N.yellow,Q="neutral",X="warn";else Z="✅ ",D=N.cyan,Q="positive",X="info";let O=L1(Q),V=`${D}[${y}] ${Z}[${Y}] [${$.toUpperCase()}]${N.reset}`;console[X](`${V}`,...W,`- ${O}`)},_={setLogLevel:x1,setCustomLogger:C1,info:T1,warn:R1,error:v1,perf:P1,levels:i};class N${setup;constructor($){this.setup=$}async handle($){try{if(X$($,this.setup._configuration.cors)){$._response._parseResponseIntoString();return}let Y=this.setup._routeRegistry._findRoute($.request.method,$.request.path);if(!Y){let w=await this.setup._hooks._onNotFound($);$._response._setBody(w),$._response._parseResponseIntoString();return}$.request.params=Y.params;let{handler:Z,options:D}=Y,{beforeHooks:Q,afterHooks:X}=D,O=this.setup._hooks._beforeAll;for(let w of O)await w.handler($);for(let w of Q)await w($);let V=null;try{V=await Z($)}catch(w){throw w}for(let w of X)await w($);let B=this.setup._hooks._afterAll;for(let w of B)await w.handler($);if($._response._setBody(V),$.request.method==="HEAD")$._response._setBody(null);$._response._parseResponseIntoString();return}catch(W){await this.handleError($,W)}}async handleError($,W){try{let Y=this.setup._hooks._onError,Z=await Y($,W);$._response._setBody(Z),X$($,this.setup._configuration.cors),$._response._parseResponseIntoString(),$._response._setHeadersIfNotSet({Date:w$.default().format("ddd, DD MMM YYYY HH:mm:ss [GMT]"),"Content-Length":$._response._stringBody.split(`
|
|
2
2
|
|
|
3
|
-
`)[1]?.length.toString()??"0"})}catch(Y){_.error("Error handler failed",Y),$.response.setStatusCode(500),$._response._setBody({success:!1,message:"Internal Server Error"}),X$($,this.setup._configuration.cors),$._response._parseResponseIntoString(),$._response._setHeadersIfNotSet({Date:w$.default().format("ddd, DD MMM YYYY HH:mm:ss [GMT]"),"Content-Length":$._response._stringBody.split(`
|
|
3
|
+
`)[1]?.length.toString()??"0"})}catch(Y){_.error("Error handler failed, this might be an internal error in the YinzerFlow framework: ",Y),$.response.setStatusCode(500),$._response._setBody({success:!1,message:"Internal Server Error"}),X$($,this.setup._configuration.cors),$._response._parseResponseIntoString(),$._response._setHeadersIfNotSet({Date:w$.default().format("ddd, DD MMM YYYY HH:mm:ss [GMT]"),"Content-Length":$._response._stringBody.split(`
|
|
4
4
|
|
|
5
5
|
`)[1]?.length.toString()??"0"})}}}var f$=["__proto__","constructor","prototype"],p$=($,W)=>{if(!$||!$.trim()||$.trim()==="\x00")return;let Y=Buffer.byteLength($,"utf8");if(Y>W.maxSize)throw _.warn("[SECURITY] JSON request body too large",{size:Y,limit:W.maxSize,sizeMB:Math.round(Y/1024/1024)}),new Error(`Request body too large: ${Y} bytes exceeds limit of ${W.maxSize} bytes`);let Z=null;try{Z=JSON.parse($)}catch(D){let Q=D instanceof Error?D.message:String(D);throw new Error(`Invalid JSON syntax: ${Q}`)}try{B$(Z,W,1)}catch(D){let Q=D instanceof Error?D.message:String(D);throw new Error(`JSON security validation failed: ${Q}`)}return Z},b1=($,W)=>{if(typeof $==="string"&&$.length>W.maxStringLength)throw new Error(`String too long: ${$.length} characters exceeds limit of ${W.maxStringLength}`)},u1=($,W,Y)=>{if($.length>W.maxArrayLength)throw new Error(`Array too large: ${$.length} elements exceeds limit of ${W.maxArrayLength}`);for(let Z of $)B$(Z,W,Y+1)},y1=($,W)=>{if($.length>W.maxKeys)throw new Error(`Object has too many keys: ${$.length} exceeds limit of ${W.maxKeys}`);if(!W.allowPrototypeProperties){for(let Y of $)if(f$.includes(Y))throw _.warn("[SECURITY] Prototype pollution attempt detected",{property:Y,dangerousProperties:f$}),new Error(`Prototype pollution attempt detected: property '${Y}' is not allowed`)}},h1=($,W,Y)=>{let Z=Object.keys($);for(let D of Z){if(D.length>W.maxStringLength)throw new Error(`Object key too long: '${D.substring(0,50)}...' exceeds limit of ${W.maxStringLength}`);let Q=$[D];if(typeof Q==="string"&&Q.length>W.maxStringLength)throw new Error(`String value too long: property '${D}' has ${Q.length} characters, exceeds limit of ${W.maxStringLength}`);B$(Q,W,Y+1)}},B$=($,W,Y)=>{if(Y>W.maxDepth)throw _.warn("[SECURITY] JSON nesting too deep - potential stack overflow attack",{currentDepth:Y,maxDepth:W.maxDepth}),new Error(`JSON nesting too deep: current depth ${Y} exceeds maximum depth of ${W.maxDepth}`);if($===null||typeof $!=="object"){b1($,W);return}if(Array.isArray($)){u1($,W,Y);return}let Z=Object.keys($);y1(Z,W),h1($,W,Y)};var m1=($)=>{let W=$.startsWith(`\r
|
|
6
6
|
`)?$.slice(2):$,Y=W.indexOf(`\r
|
|
@@ -17,6 +17,6 @@ var M1=Object.create;var{getPrototypeOf:U1,defineProperty:u$,getOwnPropertyNames
|
|
|
17
17
|
`)}
|
|
18
18
|
`:"";this._stringBody=`${$}
|
|
19
19
|
${D}
|
|
20
|
-
${Z}`;let Q=Z1(this._stringBody,this._encoding);this._setHeadersIfNotSet({Date:D1.default().format("ddd, DD MMM YYYY HH:mm:ss [GMT]"),"Content-Length":Q})}_setHeadersIfNotSet($){let W={};for(let[Z,D]of Object.entries($))if(D!==void 0&&!(Z in this._headers))W[Z]=D;let Y=k$(W);Object.assign(this._headers,Y)}_setBody($){if(this._body=$,!this._headers["content-type"]){let W=s$($);this._setHeadersIfNotSet({"Content-Type":W})}}setStatusCode($){this._statusCode=$,this._status=Y1($)}addHeaders($){let W=k$($);this._headers={...this._headers,...W}}removeHeaders($){for(let W of $)delete this._headers[W]}_setSecurityHeaders(){this._setHeadersIfNotSet({"X-Content-Type-Options":"nosniff","X-Frame-Options":"DENY","X-XSS-Protection":"1; mode=block","Referrer-Policy":"strict-origin-when-cross-origin"})}}class L${_request;_response;request;response;constructor($,W,Y){this._request=new z$($,W,Y),this._response=new I$(this._request),this.request=this._request,this.response=this._response}}var Q1={off:"off",error:"error",warn:"warn",info:"info"};var k0={enabled:!0,origin:"*",methods:["GET","POST","PUT","DELETE","PATCH","OPTIONS"],allowedHeaders:"*",exposedHeaders:[],credentials:!1,maxAge:86400,preflightContinue:!1,optionsSuccessStatus:b.noContent},O$={json:{maxSize:262144,maxDepth:10,allowPrototypeProperties:!1,maxKeys:1000,maxStringLength:1048576,maxArrayLength:1e4},fileUploads:{maxFileSize:10485760,maxTotalSize:52428800,maxFiles:10,allowedExtensions:[],blockedExtensions:[".exe",".bat",".cmd",".scr",".pif",".com"],maxFilenameLength:255},urlEncoded:{maxSize:1048576,maxFields:1000,maxFieldNameLength:100,maxFieldLength:1048576}},X1={trustedProxies:["127.0.0.1","::1"],allowPrivateIps:!0,headerPreference:["x-forwarded-for","x-real-ip","cf-connecting-ip","x-client-ip","true-client-ip"],maxChainLength:10,detectSpoofing:!0},I0={port:5000,host:"0.0.0.0",logLevel:Q1.warn,networkLogs:!1,cors:{enabled:!1},bodyParser:O$,ipSecurity:X1,connectionOptions:{socketTimeout:30000,gracefulShutdownTimeout:30000,keepAliveTimeout:65000,headersTimeout:66000},autoGracefulShutdown:!0},L0=($)=>{if($.maxSize<1)throw new Error("bodyParser.json.maxSize must be at least 1 byte");if($.maxDepth<1)throw new Error("bodyParser.json.maxDepth must be at least 1");if($.maxKeys<1)throw new Error("bodyParser.json.maxKeys must be at least 1");if($.maxStringLength<1)throw new Error("bodyParser.json.maxStringLength must be at least 1 byte");if($.maxArrayLength<1)throw new Error("bodyParser.json.maxArrayLength must be at least 1")},T0=($)=>{if($.maxFileSize<1)throw new Error("bodyParser.fileUploads.maxFileSize must be at least 1 byte");if($.maxTotalSize<1)throw new Error("bodyParser.fileUploads.maxTotalSize must be at least 1 byte");if($.maxFiles<1)throw new Error("bodyParser.fileUploads.maxFiles must be at least 1");if($.maxFilenameLength<1)throw new Error("bodyParser.fileUploads.maxFilenameLength must be at least 1 character")},R0=($)=>{if($.maxSize<1)throw new Error("bodyParser.urlEncoded.maxSize must be at least 1 byte");if($.maxFields<1)throw new Error("bodyParser.urlEncoded.maxFields must be at least 1");if($.maxFieldNameLength<1)throw new Error("bodyParser.urlEncoded.maxFieldNameLength must be at least 1 character");if($.maxFieldLength<1)throw new Error("bodyParser.urlEncoded.maxFieldLength must be at least 1 byte")},v0=($)=>{if(!Array.isArray($.trustedProxies))throw new Error("ipSecurity.trustedProxies must be an array");if(!Array.isArray($.headerPreference))throw new Error("ipSecurity.headerPreference must be an array");if($.headerPreference.length===0)throw new Error("ipSecurity.headerPreference must contain at least one header");if($.maxChainLength<1)throw new Error("ipSecurity.maxChainLength must be at least 1");if($.maxChainLength>50)throw new Error("ipSecurity.maxChainLength must not exceed 50 to prevent DoS attacks")},P0=($)=>{if($.allowPrototypeProperties)_.warn("[SECURITY WARNING] bodyParser.json.allowPrototypeProperties is enabled. This allows prototype pollution attacks. Only enable this if you absolutely need it and have other protections in place.");if($.maxSize>10485760)_.warn(`[SECURITY WARNING] bodyParser.json.maxSize is set to ${$.maxSize} bytes (${Math.round($.maxSize/1024/1024)}MB). Large JSON payloads can cause memory exhaustion and DoS attacks. Consider if this size is necessary.`);if($.maxDepth>50)_.warn(`[SECURITY WARNING] bodyParser.json.maxDepth is set to ${$.maxDepth}. Very deep JSON nesting can cause stack overflow attacks. Consider if this depth is necessary.`)},x0=($)=>{if($.maxFileSize>104857600)_.warn(`[SECURITY WARNING] bodyParser.fileUploads.maxFileSize is set to ${$.maxFileSize} bytes (${Math.round($.maxFileSize/1024/1024)}MB). Large file uploads can consume significant server resources.`);if($.maxTotalSize>1073741824)_.warn(`[SECURITY WARNING] bodyParser.fileUploads.maxTotalSize is set to ${$.maxTotalSize} bytes (${Math.round($.maxTotalSize/1024/1024/1024)}GB). Very large total upload sizes can cause memory and disk space exhaustion.`);let W=[".exe",".bat",".cmd",".scr",".pif",".com",".vbs",".jar",".app"],Y=$.allowedExtensions.filter((Z)=>W.includes(Z.toLowerCase()));if(Y.length>0)_.warn(`[SECURITY WARNING] bodyParser.fileUploads.allowedExtensions includes dangerous file types: ${Y.join(", ")}. This could allow execution of malicious files. Only allow these if absolutely necessary.`);if($.blockedExtensions.length===0&&$.allowedExtensions.length===0)_.warn("[SECURITY WARNING] File uploads have no extension restrictions (no blockedExtensions and no allowedExtensions). Consider adding blockedExtensions or allowedExtensions to improve security.")},C0=($)=>{if($.trustedProxies.length===0)_.warn("[SECURITY WARNING] ipSecurity.trustedProxies is empty. No proxy headers will be trusted, which may prevent proper client IP detection.");if($.maxChainLength>20)_.warn(`[SECURITY WARNING] ipSecurity.maxChainLength is set to ${$.maxChainLength}. Very long proxy chains can consume significant resources and may indicate amplification attacks.`);if(!$.detectSpoofing)_.warn("[SECURITY WARNING] ipSecurity.detectSpoofing is disabled. This reduces protection against IP spoofing attacks. Only disable if you have other protective measures.")},b0=($,W)=>{if(W?.cors?.enabled)$.cors={...k0,...W.cors,enabled:!0}},u0=($,W)=>{if(W?.bodyParser)$.bodyParser={json:{...O$.json,...W.bodyParser.json},fileUploads:{...O$.fileUploads,...W.bodyParser.fileUploads},urlEncoded:{...O$.urlEncoded,...W.bodyParser.urlEncoded}},m0($.bodyParser)},y0=($,W)=>{if(W?.ipSecurity)$.ipSecurity={...X1,...W.ipSecurity},v0($.ipSecurity),C0($.ipSecurity)},h0=($,W)=>{if(W?.port!==void 0){let Y=Number(W.port);if(isNaN(Y)||Y<1||Y>65535)throw new Error("Invalid port number");$.port=Y}},m0=($)=>{L0($.json),T0($.fileUploads),R0($.urlEncoded),P0($.json),x0($.fileUploads)},J1=($)=>{let W={...I0};return Object.assign(W,$),b0(W,$),u0(W,$),y0(W,$),h0(W,$),W};class T${_beforeAll;_afterAll;_onError;_onNotFound;constructor(){this._beforeAll=new Set,this._afterAll=new Set,this._onError=($)=>{return $.response.setStatusCode(b.internalServerError),{success:!1,message:"Internal Server Error"}},this._onNotFound=($)=>{return $.response.setStatusCode(b.notFound),{success:!1,message:"404 Not Found"}}}_addBeforeHooks($,W){for(let Y of $)this._beforeAll.add({handler:Y,options:W??{routesToExclude:[],routesToInclude:[]}})}_addAfterHooks($,W){for(let Y of $)this._afterAll.add({handler:Y,options:W??{routesToExclude:[],routesToInclude:[]}})}_addOnError($){this._onError=$}_addOnNotFound($){this._onNotFound=$}}var K1=($)=>{let W=[],Y=$.path.replace(/:\w+/g,(Z)=>{let D=Z.slice(1);return W.push(D),"([^/]+)"}).replace(/\//g,"\\/");return{...$,pattern:new RegExp(`^${Y}$`),paramNames:W,isParameterized:!0}};var R$=($)=>{let[W]=$.split("?");if(!W)return"";if([W]=W.split("#"),!W)return"";try{W=decodeURIComponent(W)}catch(Y){_.warn("Failed to decode URL path",{path:W})}if(W=W.startsWith("/")?W:`/${W}`,W=W.replace(/\/\/+/g,"/"),W=f0(W),W.length>1&&W.endsWith("/"))W=W.slice(0,-1);return W},f0=($)=>{let W=$.split("/"),Y=[];for(let D of W){if(D==="."||D===""){if(D===""&&Y.length===0)Y.push(D);continue}if(D===".."){if(Y.length>1)Y.pop()}else Y.push(D)}return Y.join("/")||"/"},v$=($)=>$.replace(/:\w+/g,":param");var G1=($)=>{let W=$.match(/:\w+/g);if(!W)return;let Y=W.map((D)=>D.slice(1)),Z=new Set(Y);if(Y.length!==Z.size){let D=Y.filter((Q,X)=>Y.indexOf(Q)!==X);throw new Error(`Route ${$} has duplicate parameter names: ${D.join(", ")}. Parameter names must be unique within a route for clarity and to prevent conflicts.`)}};class P${_exactRoutes=new Map;_parameterizedRoutes=new Map;_register({method:$,path:W,handler:Y,options:Z}){let D=R$(W),Q=D.includes(":");if(Q)G1(D);if(this._hasExactRoutePattern($,D))throw new Error(`Route ${D} already exists for method ${$}`);let X={method:$,path:D,handler:Y,options:Z,params:{}};if(Q)this._storeParameterizedRoute($,X);else this._storeExactRoute($,D,X)}_findRoute($,W){let Y=R$(W),Z=this._exactRoutes.get($)?.get(Y);if(Z)return Z;let D=this._findParameterizedRoute($,Y);if(D)return D;return}_hasExactRoutePattern($,W){if(this._exactRoutes.get($)?.has(W))return!0;if(W.includes(":")){let Y=v$(W),Z=this._parameterizedRoutes.get($);if(Z)return Z.some((D)=>v$(D.path)===Y)}else{let Y=this._parameterizedRoutes.get($);if(Y)return Y.some((Z)=>Z.path===W)}return!1}_storeExactRoute($,W,Y){if(!this._exactRoutes.has($))this._exactRoutes.set($,new Map);this._exactRoutes.get($)?.set(W,Y)}_storeParameterizedRoute($,W){if(!this._parameterizedRoutes.has($))this._parameterizedRoutes.set($,[]);let Y=K1(W);this._parameterizedRoutes.get($)?.push(Y)}_findParameterizedRoute($,W){let Y=this._parameterizedRoutes.get($);if(!Y)return;for(let Z of Y){let D=W.match(Z.pattern);if(D){let Q={};for(let X=0;X<Z.paramNames.length;X++){let O=D[X+1],V=Z.paramNames[X];if(O!==void 0&&V!==void 0)Q[V]=O}return{...Z,params:Q}}}return}}class x${_configuration;_routeRegistry=new P$;_hooks=new T$;constructor($){this._configuration=J1($)}get($,W,Y){let Z=Y??{beforeHooks:[],afterHooks:[]};this._routeRegistry._register({method:A.get,handler:W,path:$,options:Z,params:{}}),this._routeRegistry._register({method:A.head,handler:W,path:$,options:Z,params:{}})}head($,W,Y){this._routeRegistry._register({method:A.head,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}post($,W,Y){this._routeRegistry._register({method:A.post,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}put($,W,Y){this._routeRegistry._register({method:A.put,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}patch($,W,Y){this._routeRegistry._register({method:A.patch,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}delete($,W,Y){this._routeRegistry._register({method:A.delete,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}options($,W,Y){this._routeRegistry._register({method:A.options,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}group($,W,Y){let Z=(Q)=>(X,O,V)=>{let B=`${$}${X}`,w={beforeHooks:[...Y?.beforeHooks??[],...V?.beforeHooks??[]],afterHooks:[...V?.afterHooks??[],...Y?.afterHooks??[]]};if(this._routeRegistry._register({method:Q,handler:O,path:B,options:w,params:{}}),Q===A.get)this._routeRegistry._register({method:A.head,handler:O,path:B,options:w,params:{}})},D={get:Z(A.get),head:Z(A.head),post:Z(A.post),put:Z(A.put),delete:Z(A.delete),patch:Z(A.patch),options:Z(A.options)};W(D)}beforeAll($,W){this._hooks._addBeforeHooks($,W)}afterAll($,W){this._hooks._addAfterHooks($,W)}onError($){this._hooks._addOnError($)}onNotFound($){this._hooks._addOnNotFound($)}}class O1 extends x${_isListening=!1;_server;constructor($){super($);if(this._configuration.logger)_.setCustomLogger(this._configuration.logger);if(_.setLogLevel(this._configuration.logLevel),x.setEnabled(this._configuration.networkLogs),this._configuration.networkLogger)x.setNetworkLogger(this._configuration.networkLogger);if(_.info("YinzerFlow initialized with logging enabled",`${N.green}level: ${this._configuration.logLevel}, networkLogs: ${this._configuration.networkLogs}${N.reset}`),this._configuration.autoGracefulShutdown)this._setupGracefulShutdown()}_setupServer($,W,Y){if(!this._server)return;this._server.on("error",(Z)=>{x.serverError(this._configuration.port,this._configuration.host,Z.message),W(Z)}),this._server.on("listening",()=>{this._isListening=!0,x.serverStart(this._configuration.port,this._configuration.host),$()}),this._server.on("connection",(Z)=>{this._handleConnection(Z,Y)})}async _processRequest({data:$,socket:W,requestHandler:Y,clientAddress:Z}){let D=Date.now();_.info("Processing incoming request",{clientAddress:Z,dataSize:$.length});let Q=new L$($,this,Z);await Y.handle(Q),W.write(Q._response._stringBody),W.end();let X=Date.now(),O=X-D;if(x.request(Q,D,X),O>500)_.warn("Slow request detected",{method:Q.request.method,path:Q.request.path,statusCode:Q._response._statusCode,responseTime:`${O}ms`,clientAddress:Z})}_handleConnection($,W){let Y=$.remoteAddress??"unknown";x.connection("connect",Y),$.on("data",(Z)=>{this._processRequest({data:Z,socket:$,requestHandler:W,clientAddress:Y}).catch((D)=>{let Q=D instanceof Error?D.message:"Unknown error";x.connection("error",Y,`Unexpected error: ${Q}`),$.destroy()})}),$.on("error",(Z)=>{x.connection("error",Y,Z.message)}),$.on("close",()=>{x.connection("disconnect",Y)})}async listen(){if(this._isListening)throw new Error("Server is already listening");return new Promise(($,W)=>{let Y=new N$(this);this._server=p0(),this._setupServer($,W,Y),this._server.listen(this._configuration.port,this._configuration.host)})}async close(){if(!this._isListening||!this._server)return;return new Promise(($)=>{if(!this._server){this._isListening=!1,$();return}this._server.close(()=>{this._isListening=!1,x.serverStop(this._configuration.port,this._configuration.host),$()})})}status(){return{isListening:this._isListening,port:this._configuration.port,host:this._configuration.host}}_setupGracefulShutdown(){if(process.listenerCount("SIGTERM")===0&&process.listenerCount("SIGINT")===0){let $=(W)=>{_.info(`\uD83D\uDED1 Received ${W}, shutting down gracefully...`),this.close().then(()=>{_.info("✅ Server shut down gracefully"),process.exit(0)}).catch((Y)=>{_.error("❌ Error during graceful shutdown:",Y),process.exit(1)})};process.on("SIGTERM",()=>$("SIGTERM")),process.on("SIGINT",()=>$("SIGINT"))}}}export{_ as log,O1 as YinzerFlow};
|
|
20
|
+
${Z}`;let Q=Z1(this._stringBody,this._encoding);this._setHeadersIfNotSet({Date:D1.default().format("ddd, DD MMM YYYY HH:mm:ss [GMT]"),"Content-Length":Q})}_setHeadersIfNotSet($){let W={};for(let[Z,D]of Object.entries($))if(D!==void 0&&!(Z in this._headers))W[Z]=D;let Y=k$(W);Object.assign(this._headers,Y)}_setBody($){if(this._body=$,!this._headers["content-type"]){let W=s$($);this._setHeadersIfNotSet({"Content-Type":W})}}setStatusCode($){this._statusCode=$,this._status=Y1($)}addHeaders($){let W=k$($);this._headers={...this._headers,...W}}removeHeaders($){for(let W of $)delete this._headers[W]}_setSecurityHeaders(){this._setHeadersIfNotSet({"X-Content-Type-Options":"nosniff","X-Frame-Options":"DENY","X-XSS-Protection":"1; mode=block","Referrer-Policy":"strict-origin-when-cross-origin"})}}class L${_request;_response;request;response;constructor($,W,Y){this._request=new z$($,W,Y),this._response=new I$(this._request),this.request=this._request,this.response=this._response}}var Q1={off:"off",error:"error",warn:"warn",info:"info"};var k0={enabled:!0,origin:"*",methods:["GET","POST","PUT","DELETE","PATCH","OPTIONS"],allowedHeaders:"*",exposedHeaders:[],credentials:!1,maxAge:86400,preflightContinue:!1,optionsSuccessStatus:b.noContent},O$={json:{maxSize:262144,maxDepth:10,allowPrototypeProperties:!1,maxKeys:1000,maxStringLength:1048576,maxArrayLength:1e4},fileUploads:{maxFileSize:10485760,maxTotalSize:52428800,maxFiles:10,allowedExtensions:[],blockedExtensions:[".exe",".bat",".cmd",".scr",".pif",".com"],maxFilenameLength:255},urlEncoded:{maxSize:1048576,maxFields:1000,maxFieldNameLength:100,maxFieldLength:1048576}},X1={trustedProxies:["127.0.0.1","::1"],allowPrivateIps:!0,headerPreference:["x-forwarded-for","x-real-ip","cf-connecting-ip","x-client-ip","true-client-ip"],maxChainLength:10,detectSpoofing:!0},I0={port:5000,host:"0.0.0.0",logLevel:Q1.warn,networkLogs:!1,cors:{enabled:!1},bodyParser:O$,ipSecurity:X1,connectionOptions:{socketTimeout:30000,gracefulShutdownTimeout:30000,keepAliveTimeout:65000,headersTimeout:66000},autoGracefulShutdown:!0},L0=($)=>{if($.maxSize<1)throw new Error("bodyParser.json.maxSize must be at least 1 byte");if($.maxDepth<1)throw new Error("bodyParser.json.maxDepth must be at least 1");if($.maxKeys<1)throw new Error("bodyParser.json.maxKeys must be at least 1");if($.maxStringLength<1)throw new Error("bodyParser.json.maxStringLength must be at least 1 byte");if($.maxArrayLength<1)throw new Error("bodyParser.json.maxArrayLength must be at least 1")},T0=($)=>{if($.maxFileSize<1)throw new Error("bodyParser.fileUploads.maxFileSize must be at least 1 byte");if($.maxTotalSize<1)throw new Error("bodyParser.fileUploads.maxTotalSize must be at least 1 byte");if($.maxFiles<1)throw new Error("bodyParser.fileUploads.maxFiles must be at least 1");if($.maxFilenameLength<1)throw new Error("bodyParser.fileUploads.maxFilenameLength must be at least 1 character")},R0=($)=>{if($.maxSize<1)throw new Error("bodyParser.urlEncoded.maxSize must be at least 1 byte");if($.maxFields<1)throw new Error("bodyParser.urlEncoded.maxFields must be at least 1");if($.maxFieldNameLength<1)throw new Error("bodyParser.urlEncoded.maxFieldNameLength must be at least 1 character");if($.maxFieldLength<1)throw new Error("bodyParser.urlEncoded.maxFieldLength must be at least 1 byte")},v0=($)=>{if(!Array.isArray($.trustedProxies))throw new Error("ipSecurity.trustedProxies must be an array");if(!Array.isArray($.headerPreference))throw new Error("ipSecurity.headerPreference must be an array");if($.headerPreference.length===0)throw new Error("ipSecurity.headerPreference must contain at least one header");if($.maxChainLength<1)throw new Error("ipSecurity.maxChainLength must be at least 1");if($.maxChainLength>50)throw new Error("ipSecurity.maxChainLength must not exceed 50 to prevent DoS attacks")},P0=($)=>{if($.allowPrototypeProperties)_.warn("[SECURITY WARNING] bodyParser.json.allowPrototypeProperties is enabled. This allows prototype pollution attacks. Only enable this if you absolutely need it and have other protections in place.");if($.maxSize>10485760)_.warn(`[SECURITY WARNING] bodyParser.json.maxSize is set to ${$.maxSize} bytes (${Math.round($.maxSize/1024/1024)}MB). Large JSON payloads can cause memory exhaustion and DoS attacks. Consider if this size is necessary.`);if($.maxDepth>50)_.warn(`[SECURITY WARNING] bodyParser.json.maxDepth is set to ${$.maxDepth}. Very deep JSON nesting can cause stack overflow attacks. Consider if this depth is necessary.`)},x0=($)=>{if($.maxFileSize>104857600)_.warn(`[SECURITY WARNING] bodyParser.fileUploads.maxFileSize is set to ${$.maxFileSize} bytes (${Math.round($.maxFileSize/1024/1024)}MB). Large file uploads can consume significant server resources.`);if($.maxTotalSize>1073741824)_.warn(`[SECURITY WARNING] bodyParser.fileUploads.maxTotalSize is set to ${$.maxTotalSize} bytes (${Math.round($.maxTotalSize/1024/1024/1024)}GB). Very large total upload sizes can cause memory and disk space exhaustion.`);let W=[".exe",".bat",".cmd",".scr",".pif",".com",".vbs",".jar",".app"],Y=$.allowedExtensions.filter((Z)=>W.includes(Z.toLowerCase()));if(Y.length>0)_.warn(`[SECURITY WARNING] bodyParser.fileUploads.allowedExtensions includes dangerous file types: ${Y.join(", ")}. This could allow execution of malicious files. Only allow these if absolutely necessary.`);if($.blockedExtensions.length===0&&$.allowedExtensions.length===0)_.warn("[SECURITY WARNING] File uploads have no extension restrictions (no blockedExtensions and no allowedExtensions). Consider adding blockedExtensions or allowedExtensions to improve security.")},C0=($)=>{if($.trustedProxies.length===0)_.warn("[SECURITY WARNING] ipSecurity.trustedProxies is empty. No proxy headers will be trusted, which may prevent proper client IP detection.");if($.maxChainLength>20)_.warn(`[SECURITY WARNING] ipSecurity.maxChainLength is set to ${$.maxChainLength}. Very long proxy chains can consume significant resources and may indicate amplification attacks.`);if(!$.detectSpoofing)_.warn("[SECURITY WARNING] ipSecurity.detectSpoofing is disabled. This reduces protection against IP spoofing attacks. Only disable if you have other protective measures.")},b0=($,W)=>{if(W?.cors?.enabled)$.cors={...k0,...W.cors,enabled:!0}},u0=($,W)=>{if(W?.bodyParser)$.bodyParser={json:{...O$.json,...W.bodyParser.json},fileUploads:{...O$.fileUploads,...W.bodyParser.fileUploads},urlEncoded:{...O$.urlEncoded,...W.bodyParser.urlEncoded}},m0($.bodyParser)},y0=($,W)=>{if(W?.ipSecurity)$.ipSecurity={...X1,...W.ipSecurity},v0($.ipSecurity),C0($.ipSecurity)},h0=($,W)=>{if(W?.port!==void 0){let Y=Number(W.port);if(isNaN(Y)||Y<1||Y>65535)throw new Error("Invalid port number");$.port=Y}},m0=($)=>{L0($.json),T0($.fileUploads),R0($.urlEncoded),P0($.json),x0($.fileUploads)},J1=($)=>{let W={...I0};return Object.assign(W,$),b0(W,$),u0(W,$),y0(W,$),h0(W,$),W};class T${_beforeAll;_afterAll;_onError;_onNotFound;constructor(){this._beforeAll=new Set,this._afterAll=new Set,this._onError=($,W)=>{return _.error("Error while handeling your request: ",W),$.response.setStatusCode(b.internalServerError),{success:!1,message:"Internal Server Error"}},this._onNotFound=($)=>{return $.response.setStatusCode(b.notFound),{success:!1,message:"404 Not Found"}}}_addBeforeHooks($,W){for(let Y of $)this._beforeAll.add({handler:Y,options:W??{routesToExclude:[],routesToInclude:[]}})}_addAfterHooks($,W){for(let Y of $)this._afterAll.add({handler:Y,options:W??{routesToExclude:[],routesToInclude:[]}})}_addOnError($){this._onError=$}_addOnNotFound($){this._onNotFound=$}}var K1=($)=>{let W=[],Y=$.path.replace(/:\w+/g,(Z)=>{let D=Z.slice(1);return W.push(D),"([^/]+)"}).replace(/\//g,"\\/");return{...$,pattern:new RegExp(`^${Y}$`),paramNames:W,isParameterized:!0}};var R$=($)=>{let[W]=$.split("?");if(!W)return"";if([W]=W.split("#"),!W)return"";try{W=decodeURIComponent(W)}catch(Y){_.warn("Failed to decode URL path",{path:W})}if(W=W.startsWith("/")?W:`/${W}`,W=W.replace(/\/\/+/g,"/"),W=f0(W),W.length>1&&W.endsWith("/"))W=W.slice(0,-1);return W},f0=($)=>{let W=$.split("/"),Y=[];for(let D of W){if(D==="."||D===""){if(D===""&&Y.length===0)Y.push(D);continue}if(D===".."){if(Y.length>1)Y.pop()}else Y.push(D)}return Y.join("/")||"/"},v$=($)=>$.replace(/:\w+/g,":param");var G1=($)=>{let W=$.match(/:\w+/g);if(!W)return;let Y=W.map((D)=>D.slice(1)),Z=new Set(Y);if(Y.length!==Z.size){let D=Y.filter((Q,X)=>Y.indexOf(Q)!==X);throw new Error(`Route ${$} has duplicate parameter names: ${D.join(", ")}. Parameter names must be unique within a route for clarity and to prevent conflicts.`)}};class P${_exactRoutes=new Map;_parameterizedRoutes=new Map;_register({method:$,path:W,handler:Y,options:Z}){let D=R$(W),Q=D.includes(":");if(Q)G1(D);if(this._hasExactRoutePattern($,D))throw new Error(`Route ${D} already exists for method ${$}`);let X={method:$,path:D,handler:Y,options:Z,params:{}};if(Q)this._storeParameterizedRoute($,X);else this._storeExactRoute($,D,X)}_findRoute($,W){let Y=R$(W),Z=this._exactRoutes.get($)?.get(Y);if(Z)return Z;let D=this._findParameterizedRoute($,Y);if(D)return D;return}_hasExactRoutePattern($,W){if(this._exactRoutes.get($)?.has(W))return!0;if(W.includes(":")){let Y=v$(W),Z=this._parameterizedRoutes.get($);if(Z)return Z.some((D)=>v$(D.path)===Y)}else{let Y=this._parameterizedRoutes.get($);if(Y)return Y.some((Z)=>Z.path===W)}return!1}_storeExactRoute($,W,Y){if(!this._exactRoutes.has($))this._exactRoutes.set($,new Map);this._exactRoutes.get($)?.set(W,Y)}_storeParameterizedRoute($,W){if(!this._parameterizedRoutes.has($))this._parameterizedRoutes.set($,[]);let Y=K1(W);this._parameterizedRoutes.get($)?.push(Y)}_findParameterizedRoute($,W){let Y=this._parameterizedRoutes.get($);if(!Y)return;for(let Z of Y){let D=W.match(Z.pattern);if(D){let Q={};for(let X=0;X<Z.paramNames.length;X++){let O=D[X+1],V=Z.paramNames[X];if(O!==void 0&&V!==void 0)Q[V]=O}return{...Z,params:Q}}}return}}class x${_configuration;_routeRegistry=new P$;_hooks=new T$;constructor($){this._configuration=J1($)}get($,W,Y){let Z=Y??{beforeHooks:[],afterHooks:[]};this._routeRegistry._register({method:A.get,handler:W,path:$,options:Z,params:{}}),this._routeRegistry._register({method:A.head,handler:W,path:$,options:Z,params:{}})}head($,W,Y){this._routeRegistry._register({method:A.head,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}post($,W,Y){this._routeRegistry._register({method:A.post,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}put($,W,Y){this._routeRegistry._register({method:A.put,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}patch($,W,Y){this._routeRegistry._register({method:A.patch,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}delete($,W,Y){this._routeRegistry._register({method:A.delete,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}options($,W,Y){this._routeRegistry._register({method:A.options,handler:W,path:$,options:Y??{beforeHooks:[],afterHooks:[]},params:{}})}group($,W,Y){let Z=(Q)=>(X,O,V)=>{let B=`${$}${X}`,w={beforeHooks:[...Y?.beforeHooks??[],...V?.beforeHooks??[]],afterHooks:[...V?.afterHooks??[],...Y?.afterHooks??[]]};if(this._routeRegistry._register({method:Q,handler:O,path:B,options:w,params:{}}),Q===A.get)this._routeRegistry._register({method:A.head,handler:O,path:B,options:w,params:{}})},D={get:Z(A.get),head:Z(A.head),post:Z(A.post),put:Z(A.put),delete:Z(A.delete),patch:Z(A.patch),options:Z(A.options)};W(D)}beforeAll($,W){this._hooks._addBeforeHooks($,W)}afterAll($,W){this._hooks._addAfterHooks($,W)}onError($){this._hooks._addOnError($)}onNotFound($){this._hooks._addOnNotFound($)}}class O1 extends x${_isListening=!1;_server;constructor($){super($);if(this._configuration.logger)_.setCustomLogger(this._configuration.logger);if(_.setLogLevel(this._configuration.logLevel),x.setEnabled(this._configuration.networkLogs),this._configuration.networkLogger)x.setNetworkLogger(this._configuration.networkLogger);if(_.info("YinzerFlow initialized with logging enabled",`${N.green}level: ${this._configuration.logLevel}, networkLogs: ${this._configuration.networkLogs}${N.reset}`),this._configuration.autoGracefulShutdown)this._setupGracefulShutdown()}_setupServer($,W,Y){if(!this._server)return;this._server.on("error",(Z)=>{x.serverError(this._configuration.port,this._configuration.host,Z.message),W(Z)}),this._server.on("listening",()=>{this._isListening=!0,x.serverStart(this._configuration.port,this._configuration.host),$()}),this._server.on("connection",(Z)=>{this._handleConnection(Z,Y)})}async _processRequest({data:$,socket:W,requestHandler:Y,clientAddress:Z}){let D=Date.now();_.info("Processing incoming request",`Client: ${Z}, Data Size: ${$.length}`);let Q=new L$($,this,Z);await Y.handle(Q),W.write(Q._response._stringBody),W.end();let X=Date.now(),O=X-D;if(x.request(Q,D,X),O>500)_.warn("Slow request detected",{method:Q.request.method,path:Q.request.path,statusCode:Q._response._statusCode,responseTime:`${O}ms`,clientAddress:Z})}_handleConnection($,W){let Y=$.remoteAddress??"unknown";x.connection("connect",Y),$.on("data",(Z)=>{this._processRequest({data:Z,socket:$,requestHandler:W,clientAddress:Y}).catch((D)=>{let Q=D instanceof Error?D.message:"Unknown error";x.connection("error",Y,`Unexpected error: ${Q}`),$.destroy()})}),$.on("error",(Z)=>{x.connection("error",Y,Z.message)}),$.on("close",()=>{x.connection("disconnect",Y)})}async listen(){if(this._isListening)throw new Error("Server is already listening");return new Promise(($,W)=>{let Y=new N$(this);this._server=p0(),this._setupServer($,W,Y),this._server.listen(this._configuration.port,this._configuration.host)})}async close(){if(!this._isListening||!this._server)return;return new Promise(($)=>{if(!this._server){this._isListening=!1,$();return}this._server.close(()=>{this._isListening=!1,x.serverStop(this._configuration.port,this._configuration.host),$()})})}status(){return{isListening:this._isListening,port:this._configuration.port,host:this._configuration.host}}_setupGracefulShutdown(){if(process.listenerCount("SIGTERM")===0&&process.listenerCount("SIGINT")===0){let $=(W)=>{_.info(`\uD83D\uDED1 Received ${W}, shutting down gracefully...`),this.close().then(()=>{_.info("✅ Server shut down gracefully"),process.exit(0)}).catch((Y)=>{_.error("❌ Error during graceful shutdown:",Y),process.exit(1)})};process.on("SIGTERM",()=>$("SIGTERM")),process.on("SIGINT",()=>$("SIGINT"))}}}export{_ as log,O1 as YinzerFlow};
|
|
21
21
|
|
|
22
|
-
//# debugId=
|
|
22
|
+
//# debugId=AEA4C27F898EB43E64756E2164756E21
|