koa-classic-server 2.0.0 → 2.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +31 -17
- package/__tests__/directory-sorting-links.test.js +135 -0
- package/__tests__/ejs.test.js +299 -0
- package/__tests__/performance.test.js +75 -6
- package/__tests__/publicWwwTest/ejs-templates/complex.ejs +56 -0
- package/__tests__/publicWwwTest/ejs-templates/index.ejs +30 -0
- package/__tests__/publicWwwTest/ejs-templates/simple.ejs +13 -0
- package/__tests__/publicWwwTest/ejs-templates/with-conditional.ejs +28 -0
- package/__tests__/publicWwwTest/ejs-templates/with-escaping.ejs +26 -0
- package/__tests__/publicWwwTest/ejs-templates/with-loop.ejs +16 -0
- package/{scripts → __tests__}/setup-benchmark.js +1 -1
- package/docs/CODE_REVIEW.md +298 -0
- package/docs/FLOW_DIAGRAM.md +952 -0
- package/docs/template-engine/TEMPLATE_ENGINE_GUIDE.md +1734 -0
- package/docs/template-engine/esempi-incrementali.js +192 -0
- package/docs/template-engine/examples/esempio1-nessun-dato.ejs +12 -0
- package/docs/template-engine/examples/esempio2-una-variabile.ejs +11 -0
- package/docs/template-engine/examples/esempio3-piu-variabili.ejs +15 -0
- package/docs/template-engine/examples/esempio4-condizionale.ejs +18 -0
- package/docs/template-engine/examples/esempio5-loop.ejs +18 -0
- package/docs/template-engine/examples/index-esempi.html +181 -0
- package/docs/template-engine/examples/index.html +40 -0
- package/docs/template-engine/examples/test.ejs +64 -0
- package/index.cjs +186 -35
- package/package.json +9 -6
- package/CREATE_RELEASE.sh +0 -53
- package/publish-to-npm.sh +0 -65
- /package/{benchmark-results-baseline-v1.2.0.txt → __tests__/benchmark-results-baseline-v1.2.0.txt} +0 -0
- /package/{benchmark-results-optimized-v2.0.0.txt → __tests__/benchmark-results-optimized-v2.0.0.txt} +0 -0
- /package/{benchmark.js → __tests__/benchmark.js} +0 -0
- /package/{customTest → __tests__/customTest}/README.md +0 -0
- /package/{customTest → __tests__/customTest}/loadConfig.util.js +0 -0
- /package/{customTest → __tests__/customTest}/serversToLoad.util.js +0 -0
- /package/{demo-regex-index.js → __tests__/demo-regex-index.js} +0 -0
- /package/{test-regex-quick.js → __tests__/test-regex-quick.js} +0 -0
- /package/{BENCHMARKS.md → docs/BENCHMARKS.md} +0 -0
- /package/{CHANGELOG.md → docs/CHANGELOG.md} +0 -0
- /package/{DEBUG_REPORT.md → docs/DEBUG_REPORT.md} +0 -0
- /package/{DOCUMENTATION.md → docs/DOCUMENTATION.md} +0 -0
- /package/{EXAMPLES_INDEX_OPTION.md → docs/EXAMPLES_INDEX_OPTION.md} +0 -0
- /package/{INDEX_OPTION_PRIORITY.md → docs/INDEX_OPTION_PRIORITY.md} +0 -0
- /package/{OPTIMIZATION_HTTP_CACHING.md → docs/OPTIMIZATION_HTTP_CACHING.md} +0 -0
- /package/{PERFORMANCE_ANALYSIS.md → docs/PERFORMANCE_ANALYSIS.md} +0 -0
- /package/{PERFORMANCE_COMPARISON.md → docs/PERFORMANCE_COMPARISON.md} +0 -0
- /package/{noteExports.md → docs/noteExports.md} +0 -0
package/index.cjs
CHANGED
|
@@ -65,10 +65,10 @@ module.exports = function koaClassicServer(
|
|
|
65
65
|
options.template = opts.template || {};
|
|
66
66
|
|
|
67
67
|
options.method = Array.isArray(options.method) ? options.method : ['GET'];
|
|
68
|
-
options.showDirContents = typeof options.showDirContents
|
|
68
|
+
options.showDirContents = typeof options.showDirContents === 'boolean' ? options.showDirContents : true;
|
|
69
69
|
|
|
70
70
|
// Normalize index option to array format
|
|
71
|
-
if (typeof options.index
|
|
71
|
+
if (typeof options.index === 'string') {
|
|
72
72
|
// DEPRECATION WARNING: String format is deprecated
|
|
73
73
|
if (options.index) {
|
|
74
74
|
console.warn(
|
|
@@ -91,14 +91,14 @@ module.exports = function koaClassicServer(
|
|
|
91
91
|
options.index = [];
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
options.urlPrefix = typeof options.urlPrefix
|
|
94
|
+
options.urlPrefix = typeof options.urlPrefix === 'string' ? options.urlPrefix : "";
|
|
95
95
|
options.urlsReserved = Array.isArray(options.urlsReserved) ? options.urlsReserved : [];
|
|
96
|
-
options.template.render = (options.template.render
|
|
96
|
+
options.template.render = (options.template.render === undefined || typeof options.template.render === 'function') ? options.template.render : undefined;
|
|
97
97
|
options.template.ext = Array.isArray(options.template.ext) ? options.template.ext : [];
|
|
98
98
|
|
|
99
99
|
// OPTIMIZATION: HTTP Caching options
|
|
100
|
-
options.cacheMaxAge = typeof options.cacheMaxAge
|
|
101
|
-
options.enableCaching = typeof options.enableCaching
|
|
100
|
+
options.cacheMaxAge = typeof options.cacheMaxAge === 'number' && options.cacheMaxAge >= 0 ? options.cacheMaxAge : 3600;
|
|
101
|
+
options.enableCaching = typeof options.enableCaching === 'boolean' ? options.enableCaching : true;
|
|
102
102
|
|
|
103
103
|
return async (ctx, next) => {
|
|
104
104
|
// Check if method is allowed
|
|
@@ -109,7 +109,7 @@ module.exports = function koaClassicServer(
|
|
|
109
109
|
|
|
110
110
|
// Normalize URL (remove trailing slash)
|
|
111
111
|
let pageHref = '';
|
|
112
|
-
if (ctx.href.charAt(ctx.href.length - 1)
|
|
112
|
+
if (ctx.href.charAt(ctx.href.length - 1) === '/') {
|
|
113
113
|
pageHref = new URL(ctx.href.slice(0, -1));
|
|
114
114
|
} else {
|
|
115
115
|
pageHref = new URL(ctx.href);
|
|
@@ -120,7 +120,7 @@ module.exports = function koaClassicServer(
|
|
|
120
120
|
const a_urlPrefix = options.urlPrefix.split("/");
|
|
121
121
|
|
|
122
122
|
for (const key in a_urlPrefix) {
|
|
123
|
-
if (a_urlPrefix[key]
|
|
123
|
+
if (a_urlPrefix[key] !== a_pathname[key]) {
|
|
124
124
|
await next();
|
|
125
125
|
return;
|
|
126
126
|
}
|
|
@@ -128,7 +128,7 @@ module.exports = function koaClassicServer(
|
|
|
128
128
|
|
|
129
129
|
// Create pageHrefOutPrefix without URL prefix
|
|
130
130
|
let pageHrefOutPrefix = pageHref;
|
|
131
|
-
if (options.urlPrefix
|
|
131
|
+
if (options.urlPrefix !== "") {
|
|
132
132
|
let a_pathnameOutPrefix = a_pathname.slice(a_urlPrefix.length);
|
|
133
133
|
let s_pathnameOutPrefix = a_pathnameOutPrefix.join("/");
|
|
134
134
|
let hrefOutPrefix = pageHref.origin + '/' + s_pathnameOutPrefix;
|
|
@@ -139,7 +139,7 @@ module.exports = function koaClassicServer(
|
|
|
139
139
|
if (Array.isArray(options.urlsReserved) && options.urlsReserved.length > 0) {
|
|
140
140
|
const a_pathnameOutPrefix = pageHrefOutPrefix.pathname.split("/");
|
|
141
141
|
for (const value of options.urlsReserved) {
|
|
142
|
-
if (a_pathnameOutPrefix[1]
|
|
142
|
+
if (a_pathnameOutPrefix[1] === value.substring(1)) {
|
|
143
143
|
await next();
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
@@ -149,7 +149,7 @@ module.exports = function koaClassicServer(
|
|
|
149
149
|
// Path Traversal Protection
|
|
150
150
|
// Construct safe file path
|
|
151
151
|
let requestedPath = "";
|
|
152
|
-
if (pageHrefOutPrefix.pathname
|
|
152
|
+
if (pageHrefOutPrefix.pathname === "/") {
|
|
153
153
|
requestedPath = "";
|
|
154
154
|
} else {
|
|
155
155
|
requestedPath = decodeURIComponent(pageHrefOutPrefix.pathname);
|
|
@@ -193,7 +193,7 @@ module.exports = function koaClassicServer(
|
|
|
193
193
|
}
|
|
194
194
|
|
|
195
195
|
// No index file found, show directory listing
|
|
196
|
-
ctx.body = await show_dir(toOpen);
|
|
196
|
+
ctx.body = await show_dir(toOpen, ctx);
|
|
197
197
|
} else {
|
|
198
198
|
// Directory listing disabled
|
|
199
199
|
ctx.status = 404;
|
|
@@ -386,8 +386,20 @@ module.exports = function koaClassicServer(
|
|
|
386
386
|
ctx.body = src;
|
|
387
387
|
}
|
|
388
388
|
|
|
389
|
+
// Helper function to format file size in human-readable format
|
|
390
|
+
function formatSize(bytes) {
|
|
391
|
+
if (bytes === 0) return '0 B';
|
|
392
|
+
if (bytes === undefined || bytes === null) return '-';
|
|
393
|
+
|
|
394
|
+
const k = 1024;
|
|
395
|
+
const sizes = ['B', 'KB', 'MB', 'GB', 'TB'];
|
|
396
|
+
const i = Math.floor(Math.log(bytes) / Math.log(k));
|
|
397
|
+
|
|
398
|
+
return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
|
|
399
|
+
}
|
|
400
|
+
|
|
389
401
|
// OPTIMIZATION: show_dir is now async and uses array join instead of string concatenation
|
|
390
|
-
async function show_dir(toOpen) {
|
|
402
|
+
async function show_dir(toOpen, ctx) {
|
|
391
403
|
let dir;
|
|
392
404
|
try {
|
|
393
405
|
// OPTIMIZATION: Use async readdir (non-blocking)
|
|
@@ -409,61 +421,158 @@ module.exports = function koaClassicServer(
|
|
|
409
421
|
`;
|
|
410
422
|
}
|
|
411
423
|
|
|
424
|
+
// Get sorting parameters from query string
|
|
425
|
+
const sortBy = ctx.query.sort || 'name';
|
|
426
|
+
const sortOrder = ctx.query.order || 'asc';
|
|
427
|
+
|
|
428
|
+
// Build base URL for sorting links (without query params)
|
|
429
|
+
const baseUrl = pageHrefOutPrefix.pathname;
|
|
430
|
+
|
|
431
|
+
// Helper to create sorting URL
|
|
432
|
+
function getSortUrl(column) {
|
|
433
|
+
let newOrder = 'asc';
|
|
434
|
+
if (sortBy === column && sortOrder === 'asc') {
|
|
435
|
+
newOrder = 'desc';
|
|
436
|
+
}
|
|
437
|
+
return `${baseUrl}?sort=${column}&order=${newOrder}`;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
// Helper to get sort indicator
|
|
441
|
+
function getSortIndicator(column) {
|
|
442
|
+
if (sortBy === column) {
|
|
443
|
+
return sortOrder === 'asc' ? ' ↑' : ' ↓';
|
|
444
|
+
}
|
|
445
|
+
return '';
|
|
446
|
+
}
|
|
447
|
+
|
|
412
448
|
// OPTIMIZATION: Use array + join instead of string concatenation
|
|
413
449
|
// This reduces memory allocation from O(n²) to O(n)
|
|
414
450
|
const parts = [];
|
|
415
451
|
parts.push("<table>");
|
|
452
|
+
parts.push("<thead>");
|
|
453
|
+
parts.push("<tr>");
|
|
454
|
+
parts.push(`<th><a href="${escapeHtml(getSortUrl('name'))}">Name${getSortIndicator('name')}</a></th>`);
|
|
455
|
+
parts.push(`<th><a href="${escapeHtml(getSortUrl('type'))}">Type${getSortIndicator('type')}</a></th>`);
|
|
456
|
+
parts.push(`<th><a href="${escapeHtml(getSortUrl('size'))}">Size${getSortIndicator('size')}</a></th>`);
|
|
457
|
+
parts.push("</tr>");
|
|
458
|
+
parts.push("</thead>");
|
|
459
|
+
parts.push("<tbody>");
|
|
416
460
|
|
|
417
461
|
// Parent directory link
|
|
418
|
-
|
|
419
|
-
|
|
462
|
+
const currentPath = pageHref.origin + pageHref.pathname;
|
|
463
|
+
if (currentPath !== pageHrefOutPrefix.origin + "/") {
|
|
464
|
+
// Build parent directory URL without query parameters
|
|
465
|
+
const a_pD = currentPath.split("/");
|
|
420
466
|
a_pD.pop();
|
|
421
467
|
const parentDirectory = a_pD.join("/");
|
|
422
468
|
// Escape HTML to prevent XSS
|
|
423
|
-
parts.push(`<tr><td><a href="${escapeHtml(parentDirectory)}"><b>.. Parent Directory</b></a></td><td>DIR</td></tr>`);
|
|
469
|
+
parts.push(`<tr><td><a href="${escapeHtml(parentDirectory)}"><b>.. Parent Directory</b></a></td><td>DIR</td><td>-</td></tr>`);
|
|
424
470
|
}
|
|
425
471
|
|
|
426
|
-
if (dir.length
|
|
427
|
-
parts.push(`<tr><td>empty folder</td><td></td></tr>`);
|
|
472
|
+
if (dir.length === 0) {
|
|
473
|
+
parts.push(`<tr><td>empty folder</td><td></td><td></td></tr>`);
|
|
428
474
|
} else {
|
|
429
475
|
let a_sy = Object.getOwnPropertySymbols(dir[0]);
|
|
430
476
|
const sy_type = a_sy[0];
|
|
431
477
|
|
|
478
|
+
// Collect all items data first (for sorting)
|
|
479
|
+
const items = [];
|
|
432
480
|
for (const item of dir) {
|
|
433
481
|
const s_name = item.name.toString();
|
|
434
482
|
const type = item[sy_type];
|
|
435
483
|
|
|
436
|
-
|
|
437
|
-
if (type == 1) {
|
|
438
|
-
// File
|
|
439
|
-
rowStart = `<tr><td> FILE `;
|
|
440
|
-
} else if (type == 2 || type == 3) {
|
|
441
|
-
// Directory or symbolic link
|
|
442
|
-
rowStart = `<tr><td>`;
|
|
443
|
-
} else {
|
|
484
|
+
if (type !== 1 && type !== 2 && type !== 3) {
|
|
444
485
|
console.error("Unknown file type:", type);
|
|
445
|
-
continue;
|
|
486
|
+
continue;
|
|
446
487
|
}
|
|
447
488
|
|
|
448
489
|
const itemPath = path.join(toOpen, s_name);
|
|
449
490
|
let itemUri = "";
|
|
450
|
-
|
|
491
|
+
// Build item URI without query parameters
|
|
492
|
+
const baseUrl = pageHref.origin + pageHref.pathname;
|
|
493
|
+
if (baseUrl === pageHref.origin + options.urlPrefix + "/" || baseUrl === pageHref.origin + options.urlPrefix) {
|
|
451
494
|
itemUri = `${pageHref.origin + options.urlPrefix}/${encodeURIComponent(s_name)}`;
|
|
452
495
|
} else {
|
|
453
|
-
itemUri = `${
|
|
496
|
+
itemUri = `${baseUrl}/${encodeURIComponent(s_name)}`;
|
|
454
497
|
}
|
|
455
498
|
|
|
456
|
-
//
|
|
457
|
-
|
|
458
|
-
|
|
499
|
+
// Get file size
|
|
500
|
+
let sizeStr = '-';
|
|
501
|
+
let sizeBytes = 0;
|
|
502
|
+
try {
|
|
503
|
+
const itemStat = await fs.promises.stat(itemPath);
|
|
504
|
+
if (type === 1) {
|
|
505
|
+
sizeBytes = itemStat.size;
|
|
506
|
+
sizeStr = formatSize(sizeBytes);
|
|
507
|
+
} else {
|
|
508
|
+
sizeStr = '-';
|
|
509
|
+
}
|
|
510
|
+
} catch (error) {
|
|
511
|
+
sizeStr = '-';
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const mimeType = type === 2 ? "DIR" : (mime.lookup(itemPath) || 'unknown');
|
|
515
|
+
const isReserved = pageHrefOutPrefix.pathname === '/' && options.urlsReserved.includes('/' + s_name) && (type === 2 || type === 3);
|
|
516
|
+
|
|
517
|
+
items.push({
|
|
518
|
+
name: s_name,
|
|
519
|
+
type: type,
|
|
520
|
+
mimeType: mimeType,
|
|
521
|
+
sizeStr: sizeStr,
|
|
522
|
+
sizeBytes: sizeBytes,
|
|
523
|
+
itemUri: itemUri,
|
|
524
|
+
isReserved: isReserved
|
|
525
|
+
});
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// Sort items based on query parameters
|
|
529
|
+
items.sort((a, b) => {
|
|
530
|
+
let comparison = 0;
|
|
531
|
+
|
|
532
|
+
if (sortBy === 'name') {
|
|
533
|
+
comparison = a.name.localeCompare(b.name);
|
|
534
|
+
} else if (sortBy === 'type') {
|
|
535
|
+
// Sort directories first, then by mime type
|
|
536
|
+
if (a.type === 2 && b.type !== 2) {
|
|
537
|
+
comparison = -1;
|
|
538
|
+
} else if (a.type !== 2 && b.type === 2) {
|
|
539
|
+
comparison = 1;
|
|
540
|
+
} else {
|
|
541
|
+
comparison = a.mimeType.localeCompare(b.mimeType);
|
|
542
|
+
}
|
|
543
|
+
} else if (sortBy === 'size') {
|
|
544
|
+
// Directories always at top when sorting by size
|
|
545
|
+
if (a.type === 2 && b.type !== 2) {
|
|
546
|
+
comparison = -1;
|
|
547
|
+
} else if (a.type !== 2 && b.type === 2) {
|
|
548
|
+
comparison = 1;
|
|
549
|
+
} else {
|
|
550
|
+
comparison = a.sizeBytes - b.sizeBytes;
|
|
551
|
+
}
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Apply sort order (asc/desc)
|
|
555
|
+
return sortOrder === 'desc' ? -comparison : comparison;
|
|
556
|
+
});
|
|
557
|
+
|
|
558
|
+
// Generate HTML for sorted items
|
|
559
|
+
for (const item of items) {
|
|
560
|
+
let rowStart = '';
|
|
561
|
+
if (item.type === 1) {
|
|
562
|
+
rowStart = `<tr><td> FILE `;
|
|
459
563
|
} else {
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
564
|
+
rowStart = `<tr><td>`;
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
if (item.isReserved) {
|
|
568
|
+
parts.push(`${rowStart} ${escapeHtml(item.name)}</td> <td> DIR BUT RESERVED</td><td>${item.sizeStr}</td></tr>`);
|
|
569
|
+
} else {
|
|
570
|
+
parts.push(`${rowStart} <a href="${escapeHtml(item.itemUri)}">${escapeHtml(item.name)}</a> </td> <td> ${escapeHtml(item.mimeType)} </td><td>${item.sizeStr}</td></tr>`);
|
|
463
571
|
}
|
|
464
572
|
}
|
|
465
573
|
}
|
|
466
574
|
|
|
575
|
+
parts.push("</tbody>");
|
|
467
576
|
parts.push("</table>");
|
|
468
577
|
|
|
469
578
|
// OPTIMIZATION: Single join operation instead of multiple concatenations
|
|
@@ -477,6 +586,48 @@ module.exports = function koaClassicServer(
|
|
|
477
586
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
478
587
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
479
588
|
<title>Index of ${escapeHtml(pageHrefOutPrefix.pathname)}</title>
|
|
589
|
+
<style>
|
|
590
|
+
body {
|
|
591
|
+
font-family: Arial, sans-serif;
|
|
592
|
+
margin: 20px;
|
|
593
|
+
}
|
|
594
|
+
h1 {
|
|
595
|
+
border-bottom: 1px solid #ddd;
|
|
596
|
+
padding-bottom: 10px;
|
|
597
|
+
}
|
|
598
|
+
table {
|
|
599
|
+
border-collapse: collapse;
|
|
600
|
+
width: 100%;
|
|
601
|
+
max-width: 800px;
|
|
602
|
+
}
|
|
603
|
+
thead {
|
|
604
|
+
background-color: #f5f5f5;
|
|
605
|
+
border-bottom: 2px solid #ddd;
|
|
606
|
+
}
|
|
607
|
+
th {
|
|
608
|
+
text-align: left;
|
|
609
|
+
padding: 10px;
|
|
610
|
+
font-weight: bold;
|
|
611
|
+
border-bottom: 2px solid #ddd;
|
|
612
|
+
}
|
|
613
|
+
td {
|
|
614
|
+
padding: 8px 10px;
|
|
615
|
+
border-bottom: 1px solid #eee;
|
|
616
|
+
}
|
|
617
|
+
tr:hover {
|
|
618
|
+
background-color: #f9f9f9;
|
|
619
|
+
}
|
|
620
|
+
a {
|
|
621
|
+
color: #0066cc;
|
|
622
|
+
text-decoration: none;
|
|
623
|
+
}
|
|
624
|
+
a:hover {
|
|
625
|
+
text-decoration: underline;
|
|
626
|
+
}
|
|
627
|
+
th:nth-child(1), td:nth-child(1) { width: 50%; }
|
|
628
|
+
th:nth-child(2), td:nth-child(2) { width: 30%; }
|
|
629
|
+
th:nth-child(3), td:nth-child(3) { width: 20%; text-align: right; }
|
|
630
|
+
</style>
|
|
480
631
|
</head>
|
|
481
632
|
<body>
|
|
482
633
|
<h1>Index of ${escapeHtml(pageHrefOutPrefix.pathname)}</h1>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koa-classic-server",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.1.0",
|
|
4
4
|
"description": "High-performance Koa middleware for serving static files with Apache-like directory listing, HTTP caching, template engine support, and comprehensive security fixes",
|
|
5
5
|
"main": "index.cjs",
|
|
6
6
|
"exports": {
|
|
@@ -12,10 +12,10 @@
|
|
|
12
12
|
"test": "jest",
|
|
13
13
|
"test:security": "jest __tests__/security.test.js",
|
|
14
14
|
"test:performance": "jest __tests__/performance.test.js --runInBand",
|
|
15
|
-
"benchmark": "node benchmark.js",
|
|
16
|
-
"benchmark:save": "node benchmark.js --save",
|
|
17
|
-
"benchmark:setup": "node
|
|
18
|
-
"loadConfig": "node
|
|
15
|
+
"benchmark": "node __tests__/benchmark.js",
|
|
16
|
+
"benchmark:save": "node __tests__/benchmark.js --save",
|
|
17
|
+
"benchmark:setup": "node __tests__/setup-benchmark.js",
|
|
18
|
+
"loadConfig": "node __tests__/customTest/loadConfig.util.js"
|
|
19
19
|
},
|
|
20
20
|
"keywords": [
|
|
21
21
|
"koa",
|
|
@@ -30,11 +30,14 @@
|
|
|
30
30
|
"author": "Italo Paesano",
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"dependencies": {
|
|
33
|
-
"koa": "^3.1.1",
|
|
34
33
|
"mime-types": "^2.1.35"
|
|
35
34
|
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"koa": "^2.0.0 || ^3.0.0"
|
|
37
|
+
},
|
|
36
38
|
"devDependencies": {
|
|
37
39
|
"autocannon": "^7.15.0",
|
|
40
|
+
"ejs": "^3.1.10",
|
|
38
41
|
"inquirer": "^12.4.1",
|
|
39
42
|
"jest": "^29.7.0",
|
|
40
43
|
"supertest": "^7.0.0"
|
package/CREATE_RELEASE.sh
DELETED
|
@@ -1,53 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Script per creare la release v1.2.0
|
|
3
|
-
|
|
4
|
-
echo "🏷️ Creazione Release v1.2.0..."
|
|
5
|
-
|
|
6
|
-
# Assicurati di essere sul branch principale
|
|
7
|
-
echo "📥 Fetch delle ultime modifiche..."
|
|
8
|
-
git fetch origin
|
|
9
|
-
|
|
10
|
-
# Checkout al branch principale (prova main, poi master)
|
|
11
|
-
if git show-ref --verify --quiet refs/remotes/origin/main; then
|
|
12
|
-
echo "✅ Checkout a main..."
|
|
13
|
-
git checkout main
|
|
14
|
-
git pull origin main
|
|
15
|
-
elif git show-ref --verify --quiet refs/remotes/origin/master; then
|
|
16
|
-
echo "✅ Checkout a master..."
|
|
17
|
-
git checkout master
|
|
18
|
-
git pull origin master
|
|
19
|
-
else
|
|
20
|
-
echo "❌ Branch principale non trovato. Usa l'interfaccia GitHub."
|
|
21
|
-
exit 1
|
|
22
|
-
fi
|
|
23
|
-
|
|
24
|
-
# Crea il tag
|
|
25
|
-
echo "🏷️ Creazione tag v1.2.0..."
|
|
26
|
-
git tag -a v1.2.0 -m "Release v1.2.0 - Critical Security Update
|
|
27
|
-
|
|
28
|
-
⚠️ CRITICAL SECURITY FIXES
|
|
29
|
-
|
|
30
|
-
Security Fixes:
|
|
31
|
-
- Fixed Path Traversal Vulnerability (CRITICAL)
|
|
32
|
-
- Fixed Template Rendering Crash (CRITICAL)
|
|
33
|
-
|
|
34
|
-
Bug Fixes:
|
|
35
|
-
- HTTP Status Code 404 (HIGH)
|
|
36
|
-
- Race Condition File Access (HIGH)
|
|
37
|
-
- File Extension Extraction (HIGH)
|
|
38
|
-
- Directory Read Errors (MEDIUM)
|
|
39
|
-
- Content-Disposition Header (MEDIUM)
|
|
40
|
-
- Code Quality & XSS Protection
|
|
41
|
-
|
|
42
|
-
Statistics:
|
|
43
|
-
- Security vulnerabilities: 2 critical fixed
|
|
44
|
-
- Bugs fixed: 6
|
|
45
|
-
- Tests: 71 passing
|
|
46
|
-
- Documentation: 2000+ lines added"
|
|
47
|
-
|
|
48
|
-
# Push del tag
|
|
49
|
-
echo "📤 Push del tag a GitHub..."
|
|
50
|
-
git push origin v1.2.0
|
|
51
|
-
|
|
52
|
-
echo "✅ Tag creato! Ora vai su GitHub per creare la release:"
|
|
53
|
-
echo " https://github.com/italopaesano/koa-classic-server/releases/new?tag=v1.2.0"
|
package/publish-to-npm.sh
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# Script per pubblicare koa-classic-server v1.2.0 su npm
|
|
3
|
-
|
|
4
|
-
set -e # Exit on error
|
|
5
|
-
|
|
6
|
-
echo "📦 Publishing koa-classic-server v1.2.0 to npm"
|
|
7
|
-
echo ""
|
|
8
|
-
|
|
9
|
-
# Verifica login
|
|
10
|
-
echo "🔐 Verifying npm login..."
|
|
11
|
-
if ! npm whoami > /dev/null 2>&1; then
|
|
12
|
-
echo "❌ Not logged in to npm. Please run: npm login"
|
|
13
|
-
exit 1
|
|
14
|
-
fi
|
|
15
|
-
|
|
16
|
-
echo "✅ Logged in as: $(npm whoami)"
|
|
17
|
-
echo ""
|
|
18
|
-
|
|
19
|
-
# Verifica versione
|
|
20
|
-
echo "📋 Package info:"
|
|
21
|
-
echo " Name: $(node -p "require('./package.json').name")"
|
|
22
|
-
echo " Version: $(node -p "require('./package.json').version")"
|
|
23
|
-
echo ""
|
|
24
|
-
|
|
25
|
-
# Verifica che non ci siano modifiche non committate
|
|
26
|
-
if [ -n "$(git status --porcelain)" ]; then
|
|
27
|
-
echo "⚠️ Warning: You have uncommitted changes"
|
|
28
|
-
git status --short
|
|
29
|
-
read -p "Continue anyway? (y/N) " -n 1 -r
|
|
30
|
-
echo
|
|
31
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
32
|
-
exit 1
|
|
33
|
-
fi
|
|
34
|
-
fi
|
|
35
|
-
|
|
36
|
-
# Dry run per vedere cosa verrà pubblicato
|
|
37
|
-
echo "🔍 Files that will be published:"
|
|
38
|
-
npm pack --dry-run | tail -20
|
|
39
|
-
echo ""
|
|
40
|
-
|
|
41
|
-
# Chiedi conferma
|
|
42
|
-
read -p "🚀 Publish to npm? (y/N) " -n 1 -r
|
|
43
|
-
echo
|
|
44
|
-
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
|
45
|
-
echo "❌ Publish cancelled"
|
|
46
|
-
exit 0
|
|
47
|
-
fi
|
|
48
|
-
|
|
49
|
-
# Pubblica
|
|
50
|
-
echo "📤 Publishing to npm..."
|
|
51
|
-
npm publish
|
|
52
|
-
|
|
53
|
-
if [ $? -eq 0 ]; then
|
|
54
|
-
echo ""
|
|
55
|
-
echo "✅ Successfully published koa-classic-server@1.2.0!"
|
|
56
|
-
echo ""
|
|
57
|
-
echo "🔗 View on npm: https://www.npmjs.com/package/koa-classic-server"
|
|
58
|
-
echo ""
|
|
59
|
-
echo "📝 Users can now install with:"
|
|
60
|
-
echo " npm install koa-classic-server@1.2.0"
|
|
61
|
-
echo " npm install koa-classic-server@latest"
|
|
62
|
-
else
|
|
63
|
-
echo "❌ Publish failed"
|
|
64
|
-
exit 1
|
|
65
|
-
fi
|
/package/{benchmark-results-baseline-v1.2.0.txt → __tests__/benchmark-results-baseline-v1.2.0.txt}
RENAMED
|
File without changes
|
/package/{benchmark-results-optimized-v2.0.0.txt → __tests__/benchmark-results-optimized-v2.0.0.txt}
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|