kempo-server 1.4.3 → 1.4.6
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/.github/copilot-instructions.md +96 -96
- package/.github/workflows/publish-npm.yml +45 -0
- package/README.md +650 -650
- package/builtinMiddleware.js +136 -136
- package/defaultConfig.js +129 -129
- package/docs/.config.json +5 -5
- package/docs/.config.json.example +19 -19
- package/docs/api/user/[id]/GET.js +15 -15
- package/docs/api/user/[id]/[info]/DELETE.js +12 -12
- package/docs/api/user/[id]/[info]/GET.js +17 -17
- package/docs/api/user/[id]/[info]/POST.js +18 -18
- package/docs/api/user/[id]/[info]/PUT.js +19 -19
- package/docs/configuration.html +119 -119
- package/docs/examples.html +201 -201
- package/docs/getting-started.html +72 -72
- package/docs/index.html +81 -81
- package/docs/manifest.json +87 -87
- package/docs/middleware.html +147 -147
- package/docs/request-response.html +95 -95
- package/docs/routing.html +77 -77
- package/example-middleware.js +23 -23
- package/example.config.json +50 -50
- package/findFile.js +138 -138
- package/getFiles.js +72 -72
- package/getFlags.js +34 -34
- package/index.js +47 -47
- package/middlewareRunner.js +25 -25
- package/package.json +10 -6
- package/requestWrapper.js +87 -87
- package/responseWrapper.js +204 -204
- package/router.js +285 -285
- package/serveFile.js +71 -71
- package/tests/builtinMiddleware-cors.node-test.js +17 -17
- package/tests/builtinMiddleware.node-test.js +74 -74
- package/tests/defaultConfig.node-test.js +13 -13
- package/tests/example-middleware.node-test.js +31 -31
- package/tests/findFile.node-test.js +46 -46
- package/tests/getFiles.node-test.js +25 -25
- package/tests/getFlags.node-test.js +30 -30
- package/tests/index.node-test.js +23 -23
- package/tests/middlewareRunner.node-test.js +18 -18
- package/tests/requestWrapper.node-test.js +51 -51
- package/tests/responseWrapper.node-test.js +74 -74
- package/tests/router-middleware.node-test.js +46 -46
- package/tests/router.node-test.js +88 -88
- package/tests/serveFile.node-test.js +52 -52
- package/tests/test-utils.js +106 -106
package/builtinMiddleware.js
CHANGED
|
@@ -1,136 +1,136 @@
|
|
|
1
|
-
// Built-in middleware functions for Kempo Server
|
|
2
|
-
import zlib from 'zlib';
|
|
3
|
-
|
|
4
|
-
// CORS Middleware
|
|
5
|
-
export const corsMiddleware = (config) => {
|
|
6
|
-
return async (req, res, next) => {
|
|
7
|
-
const origin = req.headers.origin;
|
|
8
|
-
const allowedOrigins = Array.isArray(config.origin) ? config.origin : [config.origin];
|
|
9
|
-
|
|
10
|
-
if (config.origin === '*' || allowedOrigins.includes(origin)) {
|
|
11
|
-
res.setHeader('Access-Control-Allow-Origin', origin || '*');
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
|
|
15
|
-
res.setHeader('Access-Control-Allow-Headers', config.headers.join(', '));
|
|
16
|
-
|
|
17
|
-
// Handle preflight requests
|
|
18
|
-
if (req.method === 'OPTIONS') {
|
|
19
|
-
res.writeHead(200);
|
|
20
|
-
res.end();
|
|
21
|
-
return;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
await next();
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
|
|
28
|
-
// Compression Middleware
|
|
29
|
-
export const compressionMiddleware = (config) => {
|
|
30
|
-
return async (req, res, next) => {
|
|
31
|
-
const acceptEncoding = req.headers['accept-encoding'] || '';
|
|
32
|
-
|
|
33
|
-
if (!acceptEncoding.includes('gzip')) {
|
|
34
|
-
return await next();
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
const originalEnd = res.end;
|
|
38
|
-
const originalWrite = res.write;
|
|
39
|
-
const chunks = [];
|
|
40
|
-
|
|
41
|
-
res.write = function(chunk) {
|
|
42
|
-
if (chunk) chunks.push(Buffer.from(chunk));
|
|
43
|
-
return true;
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
res.end = function(chunk) {
|
|
47
|
-
if (chunk) chunks.push(Buffer.from(chunk));
|
|
48
|
-
|
|
49
|
-
const buffer = Buffer.concat(chunks);
|
|
50
|
-
|
|
51
|
-
// Only compress if above threshold
|
|
52
|
-
if (buffer.length >= config.threshold) {
|
|
53
|
-
zlib.gzip(buffer, (err, compressed) => {
|
|
54
|
-
if (!err && compressed.length < buffer.length) {
|
|
55
|
-
res.setHeader('Content-Encoding', 'gzip');
|
|
56
|
-
res.setHeader('Content-Length', compressed.length);
|
|
57
|
-
originalEnd.call(res, compressed);
|
|
58
|
-
} else {
|
|
59
|
-
originalEnd.call(res, buffer);
|
|
60
|
-
}
|
|
61
|
-
});
|
|
62
|
-
} else {
|
|
63
|
-
originalEnd.call(res, buffer);
|
|
64
|
-
}
|
|
65
|
-
};
|
|
66
|
-
|
|
67
|
-
await next();
|
|
68
|
-
};
|
|
69
|
-
};
|
|
70
|
-
|
|
71
|
-
// Rate Limiting Middleware
|
|
72
|
-
export const rateLimitMiddleware = (config) => {
|
|
73
|
-
const requestCounts = new Map();
|
|
74
|
-
|
|
75
|
-
return async (req, res, next) => {
|
|
76
|
-
const clientId = req.socket.remoteAddress;
|
|
77
|
-
const now = Date.now();
|
|
78
|
-
const windowStart = now - config.windowMs;
|
|
79
|
-
|
|
80
|
-
if (!requestCounts.has(clientId)) {
|
|
81
|
-
requestCounts.set(clientId, []);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
const requests = requestCounts.get(clientId);
|
|
85
|
-
const recentRequests = requests.filter(time => time > windowStart);
|
|
86
|
-
|
|
87
|
-
if (recentRequests.length >= config.maxRequests) {
|
|
88
|
-
res.writeHead(429, { 'Content-Type': 'text/plain' });
|
|
89
|
-
res.end(config.message);
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
recentRequests.push(now);
|
|
94
|
-
requestCounts.set(clientId, recentRequests);
|
|
95
|
-
|
|
96
|
-
await next();
|
|
97
|
-
};
|
|
98
|
-
};
|
|
99
|
-
|
|
100
|
-
// Security Headers Middleware
|
|
101
|
-
export const securityMiddleware = (config) => {
|
|
102
|
-
return async (req, res, next) => {
|
|
103
|
-
for (const [header, value] of Object.entries(config.headers)) {
|
|
104
|
-
res.setHeader(header, value);
|
|
105
|
-
}
|
|
106
|
-
await next();
|
|
107
|
-
};
|
|
108
|
-
};
|
|
109
|
-
|
|
110
|
-
// Logging Middleware
|
|
111
|
-
export const loggingMiddleware = (config, log) => {
|
|
112
|
-
return async (req, res, next) => {
|
|
113
|
-
const startTime = Date.now();
|
|
114
|
-
const userAgent = config.includeUserAgent ? req.headers['user-agent'] : '';
|
|
115
|
-
|
|
116
|
-
// Store original end to capture response
|
|
117
|
-
const originalEnd = res.end;
|
|
118
|
-
res.end = function(...args) {
|
|
119
|
-
const responseTime = Date.now() - startTime;
|
|
120
|
-
let logMessage = `${req.method} ${req.url}`;
|
|
121
|
-
|
|
122
|
-
if (config.includeResponseTime) {
|
|
123
|
-
logMessage += ` - ${responseTime}ms`;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
if (config.includeUserAgent && userAgent) {
|
|
127
|
-
logMessage += ` - ${userAgent}`;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
log(logMessage, 1);
|
|
131
|
-
originalEnd.apply(res, args);
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
await next();
|
|
135
|
-
};
|
|
136
|
-
};
|
|
1
|
+
// Built-in middleware functions for Kempo Server
|
|
2
|
+
import zlib from 'zlib';
|
|
3
|
+
|
|
4
|
+
// CORS Middleware
|
|
5
|
+
export const corsMiddleware = (config) => {
|
|
6
|
+
return async (req, res, next) => {
|
|
7
|
+
const origin = req.headers.origin;
|
|
8
|
+
const allowedOrigins = Array.isArray(config.origin) ? config.origin : [config.origin];
|
|
9
|
+
|
|
10
|
+
if (config.origin === '*' || allowedOrigins.includes(origin)) {
|
|
11
|
+
res.setHeader('Access-Control-Allow-Origin', origin || '*');
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
res.setHeader('Access-Control-Allow-Methods', config.methods.join(', '));
|
|
15
|
+
res.setHeader('Access-Control-Allow-Headers', config.headers.join(', '));
|
|
16
|
+
|
|
17
|
+
// Handle preflight requests
|
|
18
|
+
if (req.method === 'OPTIONS') {
|
|
19
|
+
res.writeHead(200);
|
|
20
|
+
res.end();
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
await next();
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Compression Middleware
|
|
29
|
+
export const compressionMiddleware = (config) => {
|
|
30
|
+
return async (req, res, next) => {
|
|
31
|
+
const acceptEncoding = req.headers['accept-encoding'] || '';
|
|
32
|
+
|
|
33
|
+
if (!acceptEncoding.includes('gzip')) {
|
|
34
|
+
return await next();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const originalEnd = res.end;
|
|
38
|
+
const originalWrite = res.write;
|
|
39
|
+
const chunks = [];
|
|
40
|
+
|
|
41
|
+
res.write = function(chunk) {
|
|
42
|
+
if (chunk) chunks.push(Buffer.from(chunk));
|
|
43
|
+
return true;
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
res.end = function(chunk) {
|
|
47
|
+
if (chunk) chunks.push(Buffer.from(chunk));
|
|
48
|
+
|
|
49
|
+
const buffer = Buffer.concat(chunks);
|
|
50
|
+
|
|
51
|
+
// Only compress if above threshold
|
|
52
|
+
if (buffer.length >= config.threshold) {
|
|
53
|
+
zlib.gzip(buffer, (err, compressed) => {
|
|
54
|
+
if (!err && compressed.length < buffer.length) {
|
|
55
|
+
res.setHeader('Content-Encoding', 'gzip');
|
|
56
|
+
res.setHeader('Content-Length', compressed.length);
|
|
57
|
+
originalEnd.call(res, compressed);
|
|
58
|
+
} else {
|
|
59
|
+
originalEnd.call(res, buffer);
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
} else {
|
|
63
|
+
originalEnd.call(res, buffer);
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
await next();
|
|
68
|
+
};
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// Rate Limiting Middleware
|
|
72
|
+
export const rateLimitMiddleware = (config) => {
|
|
73
|
+
const requestCounts = new Map();
|
|
74
|
+
|
|
75
|
+
return async (req, res, next) => {
|
|
76
|
+
const clientId = req.socket.remoteAddress;
|
|
77
|
+
const now = Date.now();
|
|
78
|
+
const windowStart = now - config.windowMs;
|
|
79
|
+
|
|
80
|
+
if (!requestCounts.has(clientId)) {
|
|
81
|
+
requestCounts.set(clientId, []);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
const requests = requestCounts.get(clientId);
|
|
85
|
+
const recentRequests = requests.filter(time => time > windowStart);
|
|
86
|
+
|
|
87
|
+
if (recentRequests.length >= config.maxRequests) {
|
|
88
|
+
res.writeHead(429, { 'Content-Type': 'text/plain' });
|
|
89
|
+
res.end(config.message);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
recentRequests.push(now);
|
|
94
|
+
requestCounts.set(clientId, recentRequests);
|
|
95
|
+
|
|
96
|
+
await next();
|
|
97
|
+
};
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// Security Headers Middleware
|
|
101
|
+
export const securityMiddleware = (config) => {
|
|
102
|
+
return async (req, res, next) => {
|
|
103
|
+
for (const [header, value] of Object.entries(config.headers)) {
|
|
104
|
+
res.setHeader(header, value);
|
|
105
|
+
}
|
|
106
|
+
await next();
|
|
107
|
+
};
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Logging Middleware
|
|
111
|
+
export const loggingMiddleware = (config, log) => {
|
|
112
|
+
return async (req, res, next) => {
|
|
113
|
+
const startTime = Date.now();
|
|
114
|
+
const userAgent = config.includeUserAgent ? req.headers['user-agent'] : '';
|
|
115
|
+
|
|
116
|
+
// Store original end to capture response
|
|
117
|
+
const originalEnd = res.end;
|
|
118
|
+
res.end = function(...args) {
|
|
119
|
+
const responseTime = Date.now() - startTime;
|
|
120
|
+
let logMessage = `${req.method} ${req.url}`;
|
|
121
|
+
|
|
122
|
+
if (config.includeResponseTime) {
|
|
123
|
+
logMessage += ` - ${responseTime}ms`;
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
if (config.includeUserAgent && userAgent) {
|
|
127
|
+
logMessage += ` - ${userAgent}`;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
log(logMessage, 1);
|
|
131
|
+
originalEnd.apply(res, args);
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
await next();
|
|
135
|
+
};
|
|
136
|
+
};
|
package/defaultConfig.js
CHANGED
|
@@ -1,130 +1,130 @@
|
|
|
1
|
-
export default {
|
|
2
|
-
allowedMimes: {
|
|
3
|
-
html: "text/html",
|
|
4
|
-
htm: "text/html",
|
|
5
|
-
shtml: "text/html",
|
|
6
|
-
css: "text/css",
|
|
7
|
-
xml: "text/xml",
|
|
8
|
-
gif: "image/gif",
|
|
9
|
-
jpeg: "image/jpeg",
|
|
10
|
-
jpg: "image/jpeg",
|
|
11
|
-
js: "application/javascript",
|
|
12
|
-
mjs: "application/javascript",
|
|
13
|
-
json: "application/json",
|
|
14
|
-
webp: "image/webp",
|
|
15
|
-
png: "image/png",
|
|
16
|
-
svg: "image/svg+xml",
|
|
17
|
-
svgz: "image/svg+xml",
|
|
18
|
-
ico: "image/x-icon",
|
|
19
|
-
webm: "video/webm",
|
|
20
|
-
mp4: "video/mp4",
|
|
21
|
-
m4v: "video/mp4",
|
|
22
|
-
ogv: "video/ogg",
|
|
23
|
-
mp3: "audio/mpeg",
|
|
24
|
-
ogg: "audio/ogg",
|
|
25
|
-
wav: "audio/wav",
|
|
26
|
-
woff: "font/woff",
|
|
27
|
-
woff2: "font/woff2",
|
|
28
|
-
ttf: "font/ttf",
|
|
29
|
-
otf: "font/otf",
|
|
30
|
-
eot: "application/vnd.ms-fontobject",
|
|
31
|
-
pdf: "application/pdf",
|
|
32
|
-
txt: "text/plain",
|
|
33
|
-
webmanifest: "application/manifest+json",
|
|
34
|
-
md: "text/markdown",
|
|
35
|
-
csv: "text/csv",
|
|
36
|
-
doc: "application/msword",
|
|
37
|
-
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
38
|
-
xls: "application/vnd.ms-excel",
|
|
39
|
-
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
40
|
-
ppt: "application/vnd.ms-powerpoint",
|
|
41
|
-
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
42
|
-
avif: "image/avif",
|
|
43
|
-
wasm: "application/wasm"
|
|
44
|
-
},
|
|
45
|
-
disallowedRegex: [
|
|
46
|
-
"^/\\..*",
|
|
47
|
-
"\\.config$",
|
|
48
|
-
"\\.env$",
|
|
49
|
-
"\\.git/",
|
|
50
|
-
"\\.htaccess$",
|
|
51
|
-
"\\.htpasswd$",
|
|
52
|
-
"^/node_modules/",
|
|
53
|
-
"^/vendor/",
|
|
54
|
-
"\\.log$",
|
|
55
|
-
"\\.bak$",
|
|
56
|
-
"\\.sql$",
|
|
57
|
-
"\\.ini$",
|
|
58
|
-
"password",
|
|
59
|
-
"config\\.php$",
|
|
60
|
-
"wp-config\\.php$",
|
|
61
|
-
"\\.DS_Store$"
|
|
62
|
-
],
|
|
63
|
-
routeFiles: [
|
|
64
|
-
'GET.js',
|
|
65
|
-
'POST.js',
|
|
66
|
-
'PUT.js',
|
|
67
|
-
'DELETE.js',
|
|
68
|
-
'HEAD.js',
|
|
69
|
-
'OPTIONS.js',
|
|
70
|
-
'PATCH.js',
|
|
71
|
-
'CONNECT.js',
|
|
72
|
-
'TRACE.js',
|
|
73
|
-
'index.js'
|
|
74
|
-
],
|
|
75
|
-
noRescanPaths: [
|
|
76
|
-
"^\\.well-known/",
|
|
77
|
-
"/favicon\\.ico$",
|
|
78
|
-
"/robots\\.txt$",
|
|
79
|
-
"/sitemap\\.xml$",
|
|
80
|
-
"/apple-touch-icon",
|
|
81
|
-
"/android-chrome-",
|
|
82
|
-
"/browserconfig\\.xml$",
|
|
83
|
-
"/manifest\\.json$",
|
|
84
|
-
"\\.map$",
|
|
85
|
-
"/__webpack_hmr$",
|
|
86
|
-
"/hot-update\\.",
|
|
87
|
-
"/sockjs-node/",
|
|
88
|
-
],
|
|
89
|
-
maxRescanAttempts: 3,
|
|
90
|
-
customRoutes: {
|
|
91
|
-
// Example: "/vendor/bootstrap.css": "./node_modules/bootstrap/dist/css/bootstrap.min.css"
|
|
92
|
-
// Wildcard example: "kempo/*": "./node_modules/kempo/dust/*"
|
|
93
|
-
},
|
|
94
|
-
middleware: {
|
|
95
|
-
// Built-in middleware configuration
|
|
96
|
-
cors: {
|
|
97
|
-
enabled: false,
|
|
98
|
-
origin: "*",
|
|
99
|
-
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
100
|
-
headers: ["Content-Type", "Authorization"]
|
|
101
|
-
},
|
|
102
|
-
compression: {
|
|
103
|
-
enabled: false,
|
|
104
|
-
threshold: 1024 // Only compress files larger than 1KB
|
|
105
|
-
},
|
|
106
|
-
rateLimit: {
|
|
107
|
-
enabled: false,
|
|
108
|
-
maxRequests: 100,
|
|
109
|
-
windowMs: 60000, // 1 minute
|
|
110
|
-
message: "Too many requests"
|
|
111
|
-
},
|
|
112
|
-
security: {
|
|
113
|
-
enabled: true,
|
|
114
|
-
headers: {
|
|
115
|
-
"X-Content-Type-Options": "nosniff",
|
|
116
|
-
"X-Frame-Options": "DENY",
|
|
117
|
-
"X-XSS-Protection": "1; mode=block"
|
|
118
|
-
}
|
|
119
|
-
},
|
|
120
|
-
logging: {
|
|
121
|
-
enabled: true,
|
|
122
|
-
includeUserAgent: false,
|
|
123
|
-
includeResponseTime: true
|
|
124
|
-
},
|
|
125
|
-
// Custom middleware files
|
|
126
|
-
custom: [
|
|
127
|
-
// Example: "./middleware/auth.js"
|
|
128
|
-
]
|
|
129
|
-
}
|
|
1
|
+
export default {
|
|
2
|
+
allowedMimes: {
|
|
3
|
+
html: "text/html",
|
|
4
|
+
htm: "text/html",
|
|
5
|
+
shtml: "text/html",
|
|
6
|
+
css: "text/css",
|
|
7
|
+
xml: "text/xml",
|
|
8
|
+
gif: "image/gif",
|
|
9
|
+
jpeg: "image/jpeg",
|
|
10
|
+
jpg: "image/jpeg",
|
|
11
|
+
js: "application/javascript",
|
|
12
|
+
mjs: "application/javascript",
|
|
13
|
+
json: "application/json",
|
|
14
|
+
webp: "image/webp",
|
|
15
|
+
png: "image/png",
|
|
16
|
+
svg: "image/svg+xml",
|
|
17
|
+
svgz: "image/svg+xml",
|
|
18
|
+
ico: "image/x-icon",
|
|
19
|
+
webm: "video/webm",
|
|
20
|
+
mp4: "video/mp4",
|
|
21
|
+
m4v: "video/mp4",
|
|
22
|
+
ogv: "video/ogg",
|
|
23
|
+
mp3: "audio/mpeg",
|
|
24
|
+
ogg: "audio/ogg",
|
|
25
|
+
wav: "audio/wav",
|
|
26
|
+
woff: "font/woff",
|
|
27
|
+
woff2: "font/woff2",
|
|
28
|
+
ttf: "font/ttf",
|
|
29
|
+
otf: "font/otf",
|
|
30
|
+
eot: "application/vnd.ms-fontobject",
|
|
31
|
+
pdf: "application/pdf",
|
|
32
|
+
txt: "text/plain",
|
|
33
|
+
webmanifest: "application/manifest+json",
|
|
34
|
+
md: "text/markdown",
|
|
35
|
+
csv: "text/csv",
|
|
36
|
+
doc: "application/msword",
|
|
37
|
+
docx: "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
|
|
38
|
+
xls: "application/vnd.ms-excel",
|
|
39
|
+
xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
|
|
40
|
+
ppt: "application/vnd.ms-powerpoint",
|
|
41
|
+
pptx: "application/vnd.openxmlformats-officedocument.presentationml.presentation",
|
|
42
|
+
avif: "image/avif",
|
|
43
|
+
wasm: "application/wasm"
|
|
44
|
+
},
|
|
45
|
+
disallowedRegex: [
|
|
46
|
+
"^/\\..*",
|
|
47
|
+
"\\.config$",
|
|
48
|
+
"\\.env$",
|
|
49
|
+
"\\.git/",
|
|
50
|
+
"\\.htaccess$",
|
|
51
|
+
"\\.htpasswd$",
|
|
52
|
+
"^/node_modules/",
|
|
53
|
+
"^/vendor/",
|
|
54
|
+
"\\.log$",
|
|
55
|
+
"\\.bak$",
|
|
56
|
+
"\\.sql$",
|
|
57
|
+
"\\.ini$",
|
|
58
|
+
"password",
|
|
59
|
+
"config\\.php$",
|
|
60
|
+
"wp-config\\.php$",
|
|
61
|
+
"\\.DS_Store$"
|
|
62
|
+
],
|
|
63
|
+
routeFiles: [
|
|
64
|
+
'GET.js',
|
|
65
|
+
'POST.js',
|
|
66
|
+
'PUT.js',
|
|
67
|
+
'DELETE.js',
|
|
68
|
+
'HEAD.js',
|
|
69
|
+
'OPTIONS.js',
|
|
70
|
+
'PATCH.js',
|
|
71
|
+
'CONNECT.js',
|
|
72
|
+
'TRACE.js',
|
|
73
|
+
'index.js'
|
|
74
|
+
],
|
|
75
|
+
noRescanPaths: [
|
|
76
|
+
"^\\.well-known/",
|
|
77
|
+
"/favicon\\.ico$",
|
|
78
|
+
"/robots\\.txt$",
|
|
79
|
+
"/sitemap\\.xml$",
|
|
80
|
+
"/apple-touch-icon",
|
|
81
|
+
"/android-chrome-",
|
|
82
|
+
"/browserconfig\\.xml$",
|
|
83
|
+
"/manifest\\.json$",
|
|
84
|
+
"\\.map$",
|
|
85
|
+
"/__webpack_hmr$",
|
|
86
|
+
"/hot-update\\.",
|
|
87
|
+
"/sockjs-node/",
|
|
88
|
+
],
|
|
89
|
+
maxRescanAttempts: 3,
|
|
90
|
+
customRoutes: {
|
|
91
|
+
// Example: "/vendor/bootstrap.css": "./node_modules/bootstrap/dist/css/bootstrap.min.css"
|
|
92
|
+
// Wildcard example: "kempo/*": "./node_modules/kempo/dust/*"
|
|
93
|
+
},
|
|
94
|
+
middleware: {
|
|
95
|
+
// Built-in middleware configuration
|
|
96
|
+
cors: {
|
|
97
|
+
enabled: false,
|
|
98
|
+
origin: "*",
|
|
99
|
+
methods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
|
|
100
|
+
headers: ["Content-Type", "Authorization"]
|
|
101
|
+
},
|
|
102
|
+
compression: {
|
|
103
|
+
enabled: false,
|
|
104
|
+
threshold: 1024 // Only compress files larger than 1KB
|
|
105
|
+
},
|
|
106
|
+
rateLimit: {
|
|
107
|
+
enabled: false,
|
|
108
|
+
maxRequests: 100,
|
|
109
|
+
windowMs: 60000, // 1 minute
|
|
110
|
+
message: "Too many requests"
|
|
111
|
+
},
|
|
112
|
+
security: {
|
|
113
|
+
enabled: true,
|
|
114
|
+
headers: {
|
|
115
|
+
"X-Content-Type-Options": "nosniff",
|
|
116
|
+
"X-Frame-Options": "DENY",
|
|
117
|
+
"X-XSS-Protection": "1; mode=block"
|
|
118
|
+
}
|
|
119
|
+
},
|
|
120
|
+
logging: {
|
|
121
|
+
enabled: true,
|
|
122
|
+
includeUserAgent: false,
|
|
123
|
+
includeResponseTime: true
|
|
124
|
+
},
|
|
125
|
+
// Custom middleware files
|
|
126
|
+
custom: [
|
|
127
|
+
// Example: "./middleware/auth.js"
|
|
128
|
+
]
|
|
129
|
+
}
|
|
130
130
|
}
|
package/docs/.config.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
{
|
|
2
|
-
"customRoutes": {
|
|
3
|
-
"/essential.css": "./node_modules/essentialcss/dist/essential.min.css",
|
|
4
|
-
"/essential-hljs.css": "./node_modules/essentialcss/dist/essential-hljs.min.css"
|
|
5
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"customRoutes": {
|
|
3
|
+
"/essential.css": "./node_modules/essentialcss/dist/essential.min.css",
|
|
4
|
+
"/essential-hljs.css": "./node_modules/essentialcss/dist/essential-hljs.min.css"
|
|
5
|
+
}
|
|
6
6
|
}
|
|
@@ -1,19 +1,19 @@
|
|
|
1
|
-
{
|
|
2
|
-
"customRoutes": {
|
|
3
|
-
"/vendor/bootstrap.css": "./node_modules/bootstrap/dist/css/bootstrap.min.css",
|
|
4
|
-
"/vendor/bootstrap.js": "./node_modules/bootstrap/dist/js/bootstrap.min.js",
|
|
5
|
-
"/vendor/jquery.js": "./node_modules/jquery/dist/jquery.min.js"
|
|
6
|
-
},
|
|
7
|
-
"allowedMimes": {
|
|
8
|
-
"woff": "font/woff",
|
|
9
|
-
"woff2": "font/woff2"
|
|
10
|
-
},
|
|
11
|
-
"disallowedRegex": [
|
|
12
|
-
"private/",
|
|
13
|
-
"\\.env$"
|
|
14
|
-
],
|
|
15
|
-
"noRescanPaths": [
|
|
16
|
-
"/vendor/"
|
|
17
|
-
],
|
|
18
|
-
"maxRescanAttempts": 3
|
|
19
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"customRoutes": {
|
|
3
|
+
"/vendor/bootstrap.css": "./node_modules/bootstrap/dist/css/bootstrap.min.css",
|
|
4
|
+
"/vendor/bootstrap.js": "./node_modules/bootstrap/dist/js/bootstrap.min.js",
|
|
5
|
+
"/vendor/jquery.js": "./node_modules/jquery/dist/jquery.min.js"
|
|
6
|
+
},
|
|
7
|
+
"allowedMimes": {
|
|
8
|
+
"woff": "font/woff",
|
|
9
|
+
"woff2": "font/woff2"
|
|
10
|
+
},
|
|
11
|
+
"disallowedRegex": [
|
|
12
|
+
"private/",
|
|
13
|
+
"\\.env$"
|
|
14
|
+
],
|
|
15
|
+
"noRescanPaths": [
|
|
16
|
+
"/vendor/"
|
|
17
|
+
],
|
|
18
|
+
"maxRescanAttempts": 3
|
|
19
|
+
}
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
export default async function(request, response) {
|
|
2
|
-
const { id } = request.params;
|
|
3
|
-
|
|
4
|
-
// Example user data
|
|
5
|
-
const userData = {
|
|
6
|
-
id: id,
|
|
7
|
-
profile: {
|
|
8
|
-
name: `${id.charAt(0).toUpperCase()}${id.slice(1)}`,
|
|
9
|
-
joinDate: '2024-01-15',
|
|
10
|
-
posts: 42
|
|
11
|
-
}
|
|
12
|
-
};
|
|
13
|
-
|
|
14
|
-
response.json(userData);
|
|
15
|
-
}
|
|
1
|
+
export default async function(request, response) {
|
|
2
|
+
const { id } = request.params;
|
|
3
|
+
|
|
4
|
+
// Example user data
|
|
5
|
+
const userData = {
|
|
6
|
+
id: id,
|
|
7
|
+
profile: {
|
|
8
|
+
name: `${id.charAt(0).toUpperCase()}${id.slice(1)}`,
|
|
9
|
+
joinDate: '2024-01-15',
|
|
10
|
+
posts: 42
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
response.json(userData);
|
|
15
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
export default async function(request, response) {
|
|
2
|
-
const { id, info } = request.params;
|
|
3
|
-
|
|
4
|
-
// Example response for deleting user info
|
|
5
|
-
const result = {
|
|
6
|
-
id: id,
|
|
7
|
-
message: 'User info deleted successfully',
|
|
8
|
-
deletedAt: new Date().toISOString()
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
response.json(result);
|
|
12
|
-
}
|
|
1
|
+
export default async function(request, response) {
|
|
2
|
+
const { id, info } = request.params;
|
|
3
|
+
|
|
4
|
+
// Example response for deleting user info
|
|
5
|
+
const result = {
|
|
6
|
+
id: id,
|
|
7
|
+
message: 'User info deleted successfully',
|
|
8
|
+
deletedAt: new Date().toISOString()
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
response.json(result);
|
|
12
|
+
}
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
export default async function(request, response) {
|
|
2
|
-
const { id, info } = request.params;
|
|
3
|
-
|
|
4
|
-
// Example detailed user info
|
|
5
|
-
const userInfo = {
|
|
6
|
-
id: id,
|
|
7
|
-
details: {
|
|
8
|
-
bio: `This is ${id}'s bio`,
|
|
9
|
-
location: 'Earth',
|
|
10
|
-
website: `https://${id}.dev`,
|
|
11
|
-
followers: 123,
|
|
12
|
-
following: 456
|
|
13
|
-
}
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
response.json(userInfo);
|
|
17
|
-
}
|
|
1
|
+
export default async function(request, response) {
|
|
2
|
+
const { id, info } = request.params;
|
|
3
|
+
|
|
4
|
+
// Example detailed user info
|
|
5
|
+
const userInfo = {
|
|
6
|
+
id: id,
|
|
7
|
+
details: {
|
|
8
|
+
bio: `This is ${id}'s bio`,
|
|
9
|
+
location: 'Earth',
|
|
10
|
+
website: `https://${id}.dev`,
|
|
11
|
+
followers: 123,
|
|
12
|
+
following: 456
|
|
13
|
+
}
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
response.json(userInfo);
|
|
17
|
+
}
|