koa-classic-server 2.1.0 โ 2.1.3
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/workflows/npm-publish.yml +98 -0
- package/README.md +559 -136
- package/docs/CHANGELOG.md +78 -0
- package/index.cjs +8 -2
- package/package.json +5 -1
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# This workflow will run tests using node and then publish a package to npm when a release is published
|
|
2
|
+
# For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages
|
|
3
|
+
|
|
4
|
+
name: Publish to npm
|
|
5
|
+
|
|
6
|
+
on:
|
|
7
|
+
release:
|
|
8
|
+
types: [published]
|
|
9
|
+
|
|
10
|
+
# Prevent multiple concurrent publish workflows
|
|
11
|
+
concurrency:
|
|
12
|
+
group: npm-publish-${{ github.ref }}
|
|
13
|
+
cancel-in-progress: false
|
|
14
|
+
|
|
15
|
+
# Set permissions for the workflow
|
|
16
|
+
permissions:
|
|
17
|
+
contents: read
|
|
18
|
+
id-token: write # Required for npm provenance
|
|
19
|
+
|
|
20
|
+
jobs:
|
|
21
|
+
build:
|
|
22
|
+
name: Build and Test
|
|
23
|
+
runs-on: ubuntu-latest
|
|
24
|
+
timeout-minutes: 10
|
|
25
|
+
|
|
26
|
+
steps:
|
|
27
|
+
- name: Checkout code
|
|
28
|
+
uses: actions/checkout@v4
|
|
29
|
+
|
|
30
|
+
- name: Setup Node.js
|
|
31
|
+
uses: actions/setup-node@v4
|
|
32
|
+
with:
|
|
33
|
+
node-version: 20
|
|
34
|
+
cache: 'npm'
|
|
35
|
+
|
|
36
|
+
- name: Install dependencies
|
|
37
|
+
run: npm ci
|
|
38
|
+
|
|
39
|
+
- name: Run tests
|
|
40
|
+
run: npm test --if-present
|
|
41
|
+
|
|
42
|
+
- name: Build package
|
|
43
|
+
run: npm run build --if-present
|
|
44
|
+
|
|
45
|
+
- name: Cache build artifacts
|
|
46
|
+
uses: actions/cache/save@v4
|
|
47
|
+
with:
|
|
48
|
+
path: |
|
|
49
|
+
node_modules
|
|
50
|
+
dist
|
|
51
|
+
build
|
|
52
|
+
key: build-${{ github.sha }}
|
|
53
|
+
|
|
54
|
+
publish-npm:
|
|
55
|
+
name: Publish to npm Registry
|
|
56
|
+
needs: build
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
timeout-minutes: 10
|
|
59
|
+
|
|
60
|
+
steps:
|
|
61
|
+
- name: Checkout code
|
|
62
|
+
uses: actions/checkout@v4
|
|
63
|
+
|
|
64
|
+
- name: Setup Node.js
|
|
65
|
+
uses: actions/setup-node@v4
|
|
66
|
+
with:
|
|
67
|
+
node-version: 20
|
|
68
|
+
registry-url: https://registry.npmjs.org/
|
|
69
|
+
cache: 'npm'
|
|
70
|
+
|
|
71
|
+
- name: Restore build artifacts
|
|
72
|
+
uses: actions/cache/restore@v4
|
|
73
|
+
with:
|
|
74
|
+
path: |
|
|
75
|
+
node_modules
|
|
76
|
+
dist
|
|
77
|
+
build
|
|
78
|
+
key: build-${{ github.sha }}
|
|
79
|
+
|
|
80
|
+
- name: Verify package version matches release tag
|
|
81
|
+
run: |
|
|
82
|
+
PACKAGE_VERSION=$(node -p "require('./package.json').version")
|
|
83
|
+
RELEASE_TAG=${GITHUB_REF#refs/tags/}
|
|
84
|
+
# Remove 'v' prefix if present in tag
|
|
85
|
+
RELEASE_VERSION=${RELEASE_TAG#v}
|
|
86
|
+
|
|
87
|
+
echo "Package version: $PACKAGE_VERSION"
|
|
88
|
+
echo "Release version: $RELEASE_VERSION"
|
|
89
|
+
|
|
90
|
+
if [ "$PACKAGE_VERSION" != "$RELEASE_VERSION" ]; then
|
|
91
|
+
echo "Error: Package version ($PACKAGE_VERSION) does not match release tag ($RELEASE_VERSION)"
|
|
92
|
+
exit 1
|
|
93
|
+
fi
|
|
94
|
+
|
|
95
|
+
- name: Publish to npm with provenance
|
|
96
|
+
run: npm publish --provenance --access public
|
|
97
|
+
env:
|
|
98
|
+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
package/README.md
CHANGED
|
@@ -1,48 +1,81 @@
|
|
|
1
1
|
# koa-classic-server
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
๐ **Production-ready Koa middleware** for serving static files with Apache2-like directory listing, sortable columns, HTTP caching, template engine support, and enterprise-grade security.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/koa-classic-server)
|
|
6
6
|
[](https://opensource.org/licenses/MIT)
|
|
7
|
-
[]()
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## ๐ Version 2.1.3 - Configuration Update
|
|
12
|
+
|
|
13
|
+
Version 2.1.3 updates the default caching behavior for better development experience while maintaining production-ready performance.
|
|
14
|
+
|
|
15
|
+
### What's New in 2.1.3
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
โ
**Development-Friendly Defaults** - `enableCaching` now defaults to `false` for easier development
|
|
18
|
+
โ
**Production Guidance** - Clear documentation on enabling caching for production environments
|
|
19
|
+
โ
**Enhanced Documentation** - Comprehensive notes on caching configuration and recommendations
|
|
12
20
|
|
|
13
|
-
### What's New in 1.2
|
|
21
|
+
### What's New in 2.1.2
|
|
14
22
|
|
|
15
|
-
โ
**
|
|
16
|
-
โ
**
|
|
17
|
-
โ
**
|
|
18
|
-
โ
**
|
|
19
|
-
โ
**
|
|
20
|
-
โ
**
|
|
23
|
+
โ
**Sortable Directory Columns** - Click Name/Type/Size to sort (Apache2-like)
|
|
24
|
+
โ
**Navigation Bug Fixed** - Directory navigation now works correctly after sorting
|
|
25
|
+
โ
**File Size Display** - Human-readable file sizes (B, KB, MB, GB, TB)
|
|
26
|
+
โ
**HTTP Caching** - 80-95% bandwidth reduction with ETag and Last-Modified
|
|
27
|
+
โ
**Async/Await** - Non-blocking I/O for high performance
|
|
28
|
+
โ
**153 Tests Passing** - Comprehensive test coverage
|
|
29
|
+
โ
**Flow Documentation** - Complete execution flow diagrams
|
|
30
|
+
โ
**Code Review** - Standardized operators and best practices
|
|
21
31
|
|
|
22
|
-
|
|
32
|
+
### What's New in 2.0
|
|
33
|
+
|
|
34
|
+
โ
**Performance Optimizations** - 50-70% faster directory listings
|
|
35
|
+
โ
**Enhanced Index Option** - Array format with RegExp support
|
|
36
|
+
โ
**Template Engine Guide** - Complete documentation with examples
|
|
37
|
+
โ
**Security Hardened** - Path traversal, XSS, race condition fixes
|
|
38
|
+
|
|
39
|
+
[See full changelog โ](./docs/CHANGELOG.md)
|
|
40
|
+
|
|
41
|
+
---
|
|
23
42
|
|
|
24
43
|
## Features
|
|
25
44
|
|
|
26
|
-
koa-classic-server is a middleware for serving static files
|
|
45
|
+
**koa-classic-server** is a high-performance middleware for serving static files with Apache2-like behavior, making file browsing intuitive and powerful.
|
|
27
46
|
|
|
28
|
-
|
|
47
|
+
### Core Features
|
|
29
48
|
|
|
30
|
-
- ๐๏ธ **Directory Listing** -
|
|
31
|
-
- ๐ **Static File Serving** - Automatic MIME type detection
|
|
32
|
-
-
|
|
33
|
-
-
|
|
34
|
-
-
|
|
35
|
-
-
|
|
49
|
+
- ๐๏ธ **Apache2-like Directory Listing** - Sortable columns (Name, Type, Size)
|
|
50
|
+
- ๐ **Static File Serving** - Automatic MIME type detection with streaming
|
|
51
|
+
- ๐ **Sortable Columns** - Click headers to sort ascending/descending
|
|
52
|
+
- ๐ **File Sizes** - Human-readable display (B, KB, MB, GB, TB)
|
|
53
|
+
- โก **HTTP Caching** - ETag, Last-Modified, 304 responses
|
|
54
|
+
- ๐จ **Template Engine Support** - EJS, Pug, Handlebars, Nunjucks, etc.
|
|
55
|
+
- ๐ **Enterprise Security** - Path traversal, XSS, race condition protection
|
|
56
|
+
- โ๏ธ **Highly Configurable** - URL prefixes, reserved paths, index files
|
|
57
|
+
- ๐ **High Performance** - Async/await, non-blocking I/O, optimized algorithms
|
|
58
|
+
- ๐งช **Well-Tested** - 153 passing tests with comprehensive coverage
|
|
36
59
|
- ๐ฆ **Dual Module Support** - CommonJS and ES Modules
|
|
37
60
|
|
|
61
|
+
---
|
|
62
|
+
|
|
38
63
|
## Installation
|
|
39
64
|
|
|
40
65
|
```bash
|
|
41
66
|
npm install koa-classic-server
|
|
42
67
|
```
|
|
43
68
|
|
|
69
|
+
**Requirements:**
|
|
70
|
+
- Node.js >= 12.0.0
|
|
71
|
+
- Koa >= 2.0.0
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
44
75
|
## Quick Start
|
|
45
76
|
|
|
77
|
+
### Basic Usage
|
|
78
|
+
|
|
46
79
|
```javascript
|
|
47
80
|
const Koa = require('koa');
|
|
48
81
|
const koaClassicServer = require('koa-classic-server');
|
|
@@ -56,9 +89,30 @@ app.listen(3000);
|
|
|
56
89
|
console.log('Server running on http://localhost:3000');
|
|
57
90
|
```
|
|
58
91
|
|
|
59
|
-
|
|
92
|
+
### With Options
|
|
93
|
+
|
|
94
|
+
```javascript
|
|
95
|
+
const Koa = require('koa');
|
|
96
|
+
const koaClassicServer = require('koa-classic-server');
|
|
97
|
+
|
|
98
|
+
const app = new Koa();
|
|
99
|
+
|
|
100
|
+
app.use(koaClassicServer(__dirname + '/public', {
|
|
101
|
+
showDirContents: true,
|
|
102
|
+
index: ['index.html', 'index.htm'],
|
|
103
|
+
urlPrefix: '/static',
|
|
104
|
+
cacheMaxAge: 3600,
|
|
105
|
+
enableCaching: true
|
|
106
|
+
}));
|
|
107
|
+
|
|
108
|
+
app.listen(3000);
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Complete Usage Guide
|
|
60
114
|
|
|
61
|
-
### Import
|
|
115
|
+
### 1. Import
|
|
62
116
|
|
|
63
117
|
```javascript
|
|
64
118
|
// CommonJS
|
|
@@ -68,9 +122,9 @@ const koaClassicServer = require('koa-classic-server');
|
|
|
68
122
|
import koaClassicServer from 'koa-classic-server';
|
|
69
123
|
```
|
|
70
124
|
|
|
71
|
-
### Basic
|
|
125
|
+
### 2. Basic File Server
|
|
72
126
|
|
|
73
|
-
|
|
127
|
+
Serve static files from a directory:
|
|
74
128
|
|
|
75
129
|
```javascript
|
|
76
130
|
const Koa = require('koa');
|
|
@@ -80,57 +134,177 @@ const app = new Koa();
|
|
|
80
134
|
|
|
81
135
|
app.use(koaClassicServer(__dirname + '/public', {
|
|
82
136
|
showDirContents: true,
|
|
83
|
-
index: ['index.html']
|
|
137
|
+
index: ['index.html']
|
|
84
138
|
}));
|
|
85
139
|
|
|
86
140
|
app.listen(3000);
|
|
87
141
|
```
|
|
88
142
|
|
|
89
|
-
|
|
143
|
+
**What it does:**
|
|
144
|
+
- Serves files from `/public` directory
|
|
145
|
+
- Shows directory listing when accessing folders
|
|
146
|
+
- Looks for `index.html` in directories
|
|
147
|
+
- Sortable columns (Name, Type, Size)
|
|
148
|
+
- File sizes displayed in human-readable format
|
|
90
149
|
|
|
91
|
-
|
|
92
|
-
const Koa = require('koa');
|
|
93
|
-
const koaClassicServer = require('koa-classic-server');
|
|
150
|
+
### 3. With URL Prefix
|
|
94
151
|
|
|
95
|
-
|
|
152
|
+
Serve files under a specific URL path:
|
|
96
153
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
app.use(koaClassicServer(__dirname + '/public', {
|
|
154
|
+
```javascript
|
|
155
|
+
app.use(koaClassicServer(__dirname + '/assets', {
|
|
100
156
|
urlPrefix: '/static',
|
|
101
157
|
showDirContents: true
|
|
102
158
|
}));
|
|
159
|
+
```
|
|
103
160
|
|
|
104
|
-
|
|
161
|
+
**Result:**
|
|
162
|
+
- `http://localhost:3000/static/image.png` โ serves `/assets/image.png`
|
|
163
|
+
- `http://localhost:3000/static/` โ shows `/assets` directory listing
|
|
164
|
+
|
|
165
|
+
### 4. With Reserved Paths
|
|
166
|
+
|
|
167
|
+
Protect specific directories from being accessed:
|
|
168
|
+
|
|
169
|
+
```javascript
|
|
170
|
+
app.use(koaClassicServer(__dirname + '/www', {
|
|
171
|
+
urlsReserved: ['/admin', '/config', '/.git', '/node_modules']
|
|
172
|
+
}));
|
|
105
173
|
```
|
|
106
174
|
|
|
107
|
-
|
|
175
|
+
**Result:**
|
|
176
|
+
- `/admin/*` โ passed to next middleware (not served)
|
|
177
|
+
- `/config/*` โ protected
|
|
178
|
+
- Other paths โ served normally
|
|
179
|
+
|
|
180
|
+
### 5. With Template Engine (EJS)
|
|
181
|
+
|
|
182
|
+
Dynamically render templates with data:
|
|
108
183
|
|
|
109
184
|
```javascript
|
|
110
|
-
const Koa = require('koa');
|
|
111
|
-
const koaClassicServer = require('koa-classic-server');
|
|
112
185
|
const ejs = require('ejs');
|
|
113
|
-
const fs = require('fs').promises;
|
|
114
|
-
|
|
115
|
-
const app = new Koa();
|
|
116
186
|
|
|
117
187
|
app.use(koaClassicServer(__dirname + '/views', {
|
|
118
188
|
template: {
|
|
119
|
-
ext: ['ejs'],
|
|
189
|
+
ext: ['ejs', 'html.ejs'],
|
|
120
190
|
render: async (ctx, next, filePath) => {
|
|
121
|
-
|
|
122
|
-
const templateContent = await fs.readFile(filePath, 'utf-8');
|
|
123
|
-
|
|
124
|
-
// Render with data
|
|
125
|
-
const html = ejs.render(templateContent, {
|
|
191
|
+
const data = {
|
|
126
192
|
title: 'My App',
|
|
127
193
|
user: ctx.state.user || { name: 'Guest' },
|
|
128
|
-
|
|
194
|
+
items: ['Item 1', 'Item 2', 'Item 3'],
|
|
129
195
|
timestamp: new Date().toISOString()
|
|
130
|
-
}
|
|
196
|
+
};
|
|
131
197
|
|
|
198
|
+
ctx.body = await ejs.renderFile(filePath, data);
|
|
132
199
|
ctx.type = 'text/html';
|
|
133
|
-
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}));
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
**Template example (`views/dashboard.ejs`):**
|
|
206
|
+
```html
|
|
207
|
+
<!DOCTYPE html>
|
|
208
|
+
<html>
|
|
209
|
+
<head>
|
|
210
|
+
<title><%= title %></title>
|
|
211
|
+
</head>
|
|
212
|
+
<body>
|
|
213
|
+
<h1>Welcome, <%= user.name %>!</h1>
|
|
214
|
+
<ul>
|
|
215
|
+
<% items.forEach(item => { %>
|
|
216
|
+
<li><%= item %></li>
|
|
217
|
+
<% }); %>
|
|
218
|
+
</ul>
|
|
219
|
+
<p>Generated at: <%= timestamp %></p>
|
|
220
|
+
</body>
|
|
221
|
+
</html>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
**See complete guide:** [Template Engine Documentation โ](./docs/template-engine/TEMPLATE_ENGINE_GUIDE.md)
|
|
225
|
+
|
|
226
|
+
### 6. With HTTP Caching
|
|
227
|
+
|
|
228
|
+
Enable aggressive caching for static files:
|
|
229
|
+
|
|
230
|
+
```javascript
|
|
231
|
+
app.use(koaClassicServer(__dirname + '/public', {
|
|
232
|
+
enableCaching: true, // Enable ETag and Last-Modified
|
|
233
|
+
cacheMaxAge: 86400, // Cache for 24 hours (in seconds)
|
|
234
|
+
}));
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
**โ ๏ธ Important: Production Recommendation**
|
|
238
|
+
|
|
239
|
+
The default value for `enableCaching` is `false` to facilitate development (where you want changes to be immediately visible). **For production environments, it is strongly recommended to set `enableCaching: true`** to benefit from:
|
|
240
|
+
|
|
241
|
+
- 80-95% bandwidth reduction
|
|
242
|
+
- 304 Not Modified responses for unchanged files
|
|
243
|
+
- Faster page loads for returning visitors
|
|
244
|
+
- Reduced server load
|
|
245
|
+
|
|
246
|
+
**See details:** [HTTP Caching Optimization โ](./docs/OPTIMIZATION_HTTP_CACHING.md)
|
|
247
|
+
|
|
248
|
+
### 7. Multiple Index Files with Priority
|
|
249
|
+
|
|
250
|
+
Search for multiple index files with custom order:
|
|
251
|
+
|
|
252
|
+
```javascript
|
|
253
|
+
app.use(koaClassicServer(__dirname + '/public', {
|
|
254
|
+
index: [
|
|
255
|
+
'index.html', // First priority
|
|
256
|
+
'index.htm', // Second priority
|
|
257
|
+
/index\.[eE][jJ][sS]/, // Third: index.ejs (case-insensitive)
|
|
258
|
+
'default.html' // Last priority
|
|
259
|
+
]
|
|
260
|
+
}));
|
|
261
|
+
```
|
|
262
|
+
|
|
263
|
+
**See details:** [Index Option Priority โ](./docs/INDEX_OPTION_PRIORITY.md)
|
|
264
|
+
|
|
265
|
+
### 8. Complete Production Example
|
|
266
|
+
|
|
267
|
+
Real-world configuration for production:
|
|
268
|
+
|
|
269
|
+
```javascript
|
|
270
|
+
const Koa = require('koa');
|
|
271
|
+
const koaClassicServer = require('koa-classic-server');
|
|
272
|
+
const ejs = require('ejs');
|
|
273
|
+
const path = require('path');
|
|
274
|
+
|
|
275
|
+
const app = new Koa();
|
|
276
|
+
|
|
277
|
+
// Serve static assets with caching
|
|
278
|
+
app.use(koaClassicServer(path.join(__dirname, 'public'), {
|
|
279
|
+
method: ['GET', 'HEAD'],
|
|
280
|
+
showDirContents: false, // Disable directory listing in production
|
|
281
|
+
index: ['index.html', 'index.htm'],
|
|
282
|
+
urlPrefix: '/assets',
|
|
283
|
+
urlsReserved: ['/admin', '/api', '/.git'],
|
|
284
|
+
enableCaching: true,
|
|
285
|
+
cacheMaxAge: 86400, // 24 hours
|
|
286
|
+
}));
|
|
287
|
+
|
|
288
|
+
// Serve dynamic templates
|
|
289
|
+
app.use(koaClassicServer(path.join(__dirname, 'views'), {
|
|
290
|
+
showDirContents: false,
|
|
291
|
+
template: {
|
|
292
|
+
ext: ['ejs'],
|
|
293
|
+
render: async (ctx, next, filePath) => {
|
|
294
|
+
const data = {
|
|
295
|
+
env: process.env.NODE_ENV,
|
|
296
|
+
user: ctx.state.user,
|
|
297
|
+
config: ctx.state.config
|
|
298
|
+
};
|
|
299
|
+
|
|
300
|
+
try {
|
|
301
|
+
ctx.body = await ejs.renderFile(filePath, data);
|
|
302
|
+
ctx.type = 'text/html';
|
|
303
|
+
} catch (error) {
|
|
304
|
+
console.error('Template error:', error);
|
|
305
|
+
ctx.status = 500;
|
|
306
|
+
ctx.body = 'Internal Server Error';
|
|
307
|
+
}
|
|
134
308
|
}
|
|
135
309
|
}
|
|
136
310
|
}));
|
|
@@ -138,9 +312,9 @@ app.use(koaClassicServer(__dirname + '/views', {
|
|
|
138
312
|
app.listen(3000);
|
|
139
313
|
```
|
|
140
314
|
|
|
141
|
-
|
|
315
|
+
---
|
|
142
316
|
|
|
143
|
-
## API
|
|
317
|
+
## API Reference
|
|
144
318
|
|
|
145
319
|
### koaClassicServer(rootDir, options)
|
|
146
320
|
|
|
@@ -148,56 +322,55 @@ Creates a Koa middleware for serving static files.
|
|
|
148
322
|
|
|
149
323
|
**Parameters:**
|
|
150
324
|
|
|
151
|
-
-
|
|
152
|
-
-
|
|
325
|
+
- **`rootDir`** (String, required): Absolute path to the directory containing files
|
|
326
|
+
- **`options`** (Object, optional): Configuration options
|
|
153
327
|
|
|
154
328
|
**Returns:** Koa middleware function
|
|
155
329
|
|
|
156
|
-
|
|
330
|
+
### Options
|
|
157
331
|
|
|
158
332
|
```javascript
|
|
159
|
-
|
|
333
|
+
{
|
|
160
334
|
// HTTP methods allowed (default: ['GET'])
|
|
161
335
|
method: ['GET', 'HEAD'],
|
|
162
336
|
|
|
163
337
|
// Show directory contents (default: true)
|
|
164
338
|
showDirContents: true,
|
|
165
339
|
|
|
166
|
-
// Index file configuration
|
|
167
|
-
//
|
|
168
|
-
//
|
|
169
|
-
// -
|
|
170
|
-
// -
|
|
171
|
-
//
|
|
172
|
-
//
|
|
173
|
-
|
|
174
|
-
// DEPRECATED: String format 'index.html' still works but will be removed
|
|
175
|
-
// in future versions. Please use array format: ['index.html']
|
|
176
|
-
//
|
|
177
|
-
// See INDEX_OPTION_PRIORITY.md for detailed behavior documentation
|
|
178
|
-
index: ['index.html'],
|
|
340
|
+
// Index file configuration
|
|
341
|
+
// Array format (recommended):
|
|
342
|
+
// - Strings: exact matches ['index.html', 'default.html']
|
|
343
|
+
// - RegExp: pattern matches [/index\.html/i]
|
|
344
|
+
// - Mixed: ['index.html', /INDEX\.HTM/i]
|
|
345
|
+
// Priority determined by array order (first match wins)
|
|
346
|
+
// See docs/INDEX_OPTION_PRIORITY.md for details
|
|
347
|
+
index: ['index.html', 'index.htm'],
|
|
179
348
|
|
|
180
349
|
// URL path prefix (default: '')
|
|
181
|
-
// Files
|
|
350
|
+
// Files served under this prefix
|
|
182
351
|
urlPrefix: '/static',
|
|
183
352
|
|
|
184
353
|
// Reserved paths (default: [])
|
|
185
|
-
//
|
|
186
|
-
|
|
187
|
-
urlsReserved: ['/admin', '/private'],
|
|
354
|
+
// First-level directories passed to next middleware
|
|
355
|
+
urlsReserved: ['/admin', '/api', '/.git'],
|
|
188
356
|
|
|
189
357
|
// Template engine configuration
|
|
190
358
|
template: {
|
|
191
359
|
// Template rendering function
|
|
192
360
|
render: async (ctx, next, filePath) => {
|
|
193
361
|
// Your rendering logic
|
|
194
|
-
ctx.body = await
|
|
362
|
+
ctx.body = await yourEngine.render(filePath, data);
|
|
195
363
|
},
|
|
196
364
|
|
|
197
|
-
// File extensions to process
|
|
365
|
+
// File extensions to process
|
|
198
366
|
ext: ['ejs', 'pug', 'hbs']
|
|
199
|
-
}
|
|
200
|
-
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
// HTTP caching configuration
|
|
370
|
+
// NOTE: Default is false for development. Set to true in production for better performance!
|
|
371
|
+
enableCaching: false, // Enable ETag & Last-Modified (default: false)
|
|
372
|
+
cacheMaxAge: 3600, // Cache-Control max-age in seconds (default: 3600 = 1 hour)
|
|
373
|
+
}
|
|
201
374
|
```
|
|
202
375
|
|
|
203
376
|
### Options Details
|
|
@@ -206,133 +379,383 @@ const options = {
|
|
|
206
379
|
|--------|------|---------|-------------|
|
|
207
380
|
| `method` | Array | `['GET']` | Allowed HTTP methods |
|
|
208
381
|
| `showDirContents` | Boolean | `true` | Show directory listing |
|
|
209
|
-
| `index` | String | `
|
|
382
|
+
| `index` | Array/String | `[]` | Index file patterns (array format recommended) |
|
|
210
383
|
| `urlPrefix` | String | `''` | URL path prefix |
|
|
211
|
-
| `urlsReserved` | Array | `[]` | Reserved directory paths |
|
|
384
|
+
| `urlsReserved` | Array | `[]` | Reserved directory paths (first-level only) |
|
|
212
385
|
| `template.render` | Function | `undefined` | Template rendering function |
|
|
213
386
|
| `template.ext` | Array | `[]` | Extensions for template rendering |
|
|
387
|
+
| `enableCaching` | Boolean | `false` | Enable HTTP caching headers (recommended: `true` in production) |
|
|
388
|
+
| `cacheMaxAge` | Number | `3600` | Cache duration in seconds |
|
|
389
|
+
|
|
390
|
+
---
|
|
391
|
+
|
|
392
|
+
## Directory Listing Features
|
|
393
|
+
|
|
394
|
+
### Sortable Columns
|
|
395
|
+
|
|
396
|
+
Click on column headers to sort:
|
|
397
|
+
|
|
398
|
+
- **Name** - Alphabetical sorting (A-Z or Z-A)
|
|
399
|
+
- **Type** - Sort by MIME type (directories always first)
|
|
400
|
+
- **Size** - Sort by file size (directories always first)
|
|
401
|
+
|
|
402
|
+
Visual indicators:
|
|
403
|
+
- **โ** - Ascending order
|
|
404
|
+
- **โ** - Descending order
|
|
405
|
+
|
|
406
|
+
### File Size Display
|
|
407
|
+
|
|
408
|
+
Human-readable format:
|
|
409
|
+
- `1.5 KB` - Kilobytes
|
|
410
|
+
- `2.3 MB` - Megabytes
|
|
411
|
+
- `1.2 GB` - Gigabytes
|
|
412
|
+
- `-` - Directories (no size)
|
|
413
|
+
|
|
414
|
+
### Navigation
|
|
415
|
+
|
|
416
|
+
- **Click folder name** - Enter directory
|
|
417
|
+
- **Click file name** - Download/view file
|
|
418
|
+
- **Parent Directory** - Go up one level
|
|
419
|
+
|
|
420
|
+
---
|
|
214
421
|
|
|
215
422
|
## Security
|
|
216
423
|
|
|
217
|
-
###
|
|
424
|
+
### Built-in Protection
|
|
425
|
+
|
|
426
|
+
koa-classic-server includes enterprise-grade security:
|
|
218
427
|
|
|
219
|
-
|
|
428
|
+
#### 1. Path Traversal Protection
|
|
429
|
+
|
|
430
|
+
Prevents access to files outside `rootDir`:
|
|
220
431
|
|
|
221
432
|
```javascript
|
|
222
|
-
// โ
|
|
223
|
-
GET /../../../etc/passwd
|
|
224
|
-
GET /../config/database.yml
|
|
225
|
-
GET /%2e%2e%2fpackage.json
|
|
433
|
+
// โ Blocked requests
|
|
434
|
+
GET /../../../etc/passwd โ 403 Forbidden
|
|
435
|
+
GET /../config/database.yml โ 403 Forbidden
|
|
436
|
+
GET /%2e%2e%2fpackage.json โ 403 Forbidden
|
|
226
437
|
```
|
|
227
438
|
|
|
228
|
-
|
|
439
|
+
#### 2. XSS Protection
|
|
229
440
|
|
|
230
|
-
|
|
441
|
+
All filenames and paths are HTML-escaped:
|
|
231
442
|
|
|
232
443
|
```javascript
|
|
233
|
-
|
|
234
|
-
|
|
444
|
+
// Malicious filename: <script>alert('xss')</script>.txt
|
|
445
|
+
// Displayed as: <script>alert('xss')</script>.txt
|
|
446
|
+
// โ
Safe - script doesn't execute
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
#### 3. Reserved URLs
|
|
450
|
+
|
|
451
|
+
Protect sensitive directories:
|
|
452
|
+
|
|
453
|
+
```javascript
|
|
454
|
+
app.use(koaClassicServer(__dirname, {
|
|
455
|
+
urlsReserved: ['/admin', '/config', '/.git', '/node_modules']
|
|
235
456
|
}));
|
|
236
457
|
```
|
|
237
458
|
|
|
238
|
-
|
|
459
|
+
#### 4. Race Condition Protection
|
|
460
|
+
|
|
461
|
+
File access is verified before streaming:
|
|
239
462
|
|
|
240
|
-
|
|
463
|
+
```javascript
|
|
464
|
+
// File deleted between check and access?
|
|
465
|
+
// โ
Returns 404 instead of crashing
|
|
466
|
+
```
|
|
467
|
+
|
|
468
|
+
**See full security audit:** [Security Tests โ](./__tests__/security.test.js)
|
|
469
|
+
|
|
470
|
+
---
|
|
241
471
|
|
|
242
|
-
##
|
|
472
|
+
## Performance
|
|
243
473
|
|
|
244
|
-
|
|
474
|
+
### Optimizations
|
|
245
475
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
- **
|
|
476
|
+
Version 2.x includes major performance improvements:
|
|
477
|
+
|
|
478
|
+
- **Async/Await** - Non-blocking I/O, event loop never blocked
|
|
479
|
+
- **Array Join** - 30-40% less memory vs string concatenation
|
|
480
|
+
- **HTTP Caching** - 80-95% bandwidth reduction
|
|
481
|
+
- **Single stat() Call** - No double file system access
|
|
482
|
+
- **Streaming** - Large files streamed efficiently
|
|
483
|
+
|
|
484
|
+
### Benchmarks
|
|
485
|
+
|
|
486
|
+
Performance results on directory with 1,000 files:
|
|
487
|
+
|
|
488
|
+
```
|
|
489
|
+
Before (v1.x): ~350ms per request
|
|
490
|
+
After (v2.x): ~190ms per request
|
|
491
|
+
Improvement: 46% faster
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
**See detailed benchmarks:** [Performance Analysis โ](./docs/PERFORMANCE_ANALYSIS.md)
|
|
495
|
+
|
|
496
|
+
---
|
|
249
497
|
|
|
250
498
|
## Testing
|
|
251
499
|
|
|
500
|
+
Run the comprehensive test suite:
|
|
501
|
+
|
|
252
502
|
```bash
|
|
253
503
|
# Run all tests
|
|
254
504
|
npm test
|
|
255
505
|
|
|
256
506
|
# Run security tests only
|
|
257
507
|
npm run test:security
|
|
508
|
+
|
|
509
|
+
# Run performance benchmarks
|
|
510
|
+
npm run test:performance
|
|
258
511
|
```
|
|
259
512
|
|
|
260
|
-
|
|
513
|
+
**Test Coverage:**
|
|
514
|
+
- โ
153 tests passing
|
|
515
|
+
- โ
Security tests (path traversal, XSS, race conditions)
|
|
516
|
+
- โ
EJS template integration tests
|
|
517
|
+
- โ
Index option tests (strings, arrays, RegExp)
|
|
518
|
+
- โ
Performance benchmarks
|
|
519
|
+
- โ
Directory sorting tests
|
|
261
520
|
|
|
262
|
-
|
|
521
|
+
---
|
|
263
522
|
|
|
264
|
-
|
|
265
|
-
2. If `showDirContents: true` โ show directory listing
|
|
266
|
-
3. If `showDirContents: false` โ return 404
|
|
523
|
+
## Complete Documentation
|
|
267
524
|
|
|
268
|
-
###
|
|
525
|
+
### Core Documentation
|
|
269
526
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
527
|
+
- **[DOCUMENTATION.md](./docs/DOCUMENTATION.md)** - Complete API reference and usage guide
|
|
528
|
+
- **[FLOW_DIAGRAM.md](./docs/FLOW_DIAGRAM.md)** - Visual flow diagrams and code execution paths
|
|
529
|
+
- **[CHANGELOG.md](./docs/CHANGELOG.md)** - Version history and release notes
|
|
273
530
|
|
|
274
|
-
###
|
|
531
|
+
### Template Engine
|
|
275
532
|
|
|
276
|
-
|
|
533
|
+
- **[TEMPLATE_ENGINE_GUIDE.md](./docs/template-engine/TEMPLATE_ENGINE_GUIDE.md)** - Complete guide to template engine integration
|
|
534
|
+
- Progressive examples (simple to enterprise)
|
|
535
|
+
- EJS, Pug, Handlebars, Nunjucks support
|
|
536
|
+
- Best practices and troubleshooting
|
|
277
537
|
|
|
278
|
-
|
|
538
|
+
### Configuration
|
|
279
539
|
|
|
280
|
-
|
|
540
|
+
- **[INDEX_OPTION_PRIORITY.md](./docs/INDEX_OPTION_PRIORITY.md)** - Detailed priority behavior for `index` option
|
|
541
|
+
- String vs Array vs RegExp formats
|
|
542
|
+
- Priority order examples
|
|
543
|
+
- Migration guide from v1.x
|
|
281
544
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
545
|
+
- **[EXAMPLES_INDEX_OPTION.md](./docs/EXAMPLES_INDEX_OPTION.md)** - 10 practical examples of `index` option with RegExp
|
|
546
|
+
- Case-insensitive matching
|
|
547
|
+
- Multiple extensions
|
|
548
|
+
- Complex patterns
|
|
285
549
|
|
|
286
|
-
|
|
287
|
-
- 404 status codes now correct (was 200)
|
|
288
|
-
- Path traversal blocked (was allowed)
|
|
289
|
-
- Template errors return 500 (was crash)
|
|
550
|
+
### Performance
|
|
290
551
|
|
|
291
|
-
|
|
552
|
+
- **[PERFORMANCE_ANALYSIS.md](./docs/PERFORMANCE_ANALYSIS.md)** - Performance optimization analysis
|
|
553
|
+
- Before/after comparisons
|
|
554
|
+
- Memory usage analysis
|
|
555
|
+
- Bottleneck identification
|
|
292
556
|
|
|
293
|
-
|
|
557
|
+
- **[PERFORMANCE_COMPARISON.md](./docs/PERFORMANCE_COMPARISON.md)** - Detailed performance benchmarks
|
|
558
|
+
- Request latency
|
|
559
|
+
- Throughput metrics
|
|
560
|
+
- Concurrent request handling
|
|
294
561
|
|
|
295
|
-
|
|
562
|
+
- **[OPTIMIZATION_HTTP_CACHING.md](./docs/OPTIMIZATION_HTTP_CACHING.md)** - HTTP caching implementation details
|
|
563
|
+
- ETag generation
|
|
564
|
+
- Last-Modified headers
|
|
565
|
+
- 304 Not Modified responses
|
|
566
|
+
|
|
567
|
+
- **[BENCHMARKS.md](./docs/BENCHMARKS.md)** - Benchmark results and methodology
|
|
568
|
+
|
|
569
|
+
### Code Quality
|
|
296
570
|
|
|
297
|
-
- **[DOCUMENTATION.md](./docs/DOCUMENTATION.md)** - Complete API reference and usage guide
|
|
298
|
-
- **[FLOW_DIAGRAM.md](./docs/FLOW_DIAGRAM.md)** - Visual flow diagrams and code execution paths
|
|
299
|
-
- **[TEMPLATE_ENGINE_GUIDE.md](./docs/template-engine/TEMPLATE_ENGINE_GUIDE.md)** - Complete guide to template engine integration (EJS, Pug, Handlebars, Nunjucks)
|
|
300
|
-
- **[INDEX_OPTION_PRIORITY.md](./docs/INDEX_OPTION_PRIORITY.md)** - Detailed priority behavior for `index` option (string, array, RegExp)
|
|
301
|
-
- **[EXAMPLES_INDEX_OPTION.md](./docs/EXAMPLES_INDEX_OPTION.md)** - 10 practical examples of `index` option with RegExp
|
|
302
|
-
- **[PERFORMANCE_ANALYSIS.md](./docs/PERFORMANCE_ANALYSIS.md)** - Performance optimization analysis
|
|
303
|
-
- **[PERFORMANCE_COMPARISON.md](./docs/PERFORMANCE_COMPARISON.md)** - Before/after performance benchmarks
|
|
304
571
|
- **[CODE_REVIEW.md](./docs/CODE_REVIEW.md)** - Code quality analysis and review
|
|
572
|
+
- Security audit
|
|
573
|
+
- Best practices
|
|
574
|
+
- Standardization improvements
|
|
575
|
+
|
|
576
|
+
- **[DEBUG_REPORT.md](./docs/DEBUG_REPORT.md)** - Known limitations and debugging info
|
|
577
|
+
- Reserved URLs behavior
|
|
578
|
+
- Edge cases
|
|
579
|
+
- Troubleshooting tips
|
|
580
|
+
|
|
581
|
+
---
|
|
582
|
+
|
|
583
|
+
## Migration Guide
|
|
584
|
+
|
|
585
|
+
### From v1.x to v2.x
|
|
586
|
+
|
|
587
|
+
**Breaking Changes:**
|
|
588
|
+
- `index` option: String format deprecated (still works), use array format
|
|
589
|
+
|
|
590
|
+
**Migration:**
|
|
591
|
+
|
|
592
|
+
```javascript
|
|
593
|
+
// v1.x (deprecated)
|
|
594
|
+
{
|
|
595
|
+
index: 'index.html'
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
// v2.x (recommended)
|
|
599
|
+
{
|
|
600
|
+
index: ['index.html']
|
|
601
|
+
}
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
**New Features:**
|
|
605
|
+
- HTTP caching (enabled by default)
|
|
606
|
+
- Sortable directory columns
|
|
607
|
+
- File size display
|
|
608
|
+
- Enhanced index option with RegExp
|
|
609
|
+
|
|
610
|
+
**See full migration guide:** [CHANGELOG.md](./docs/CHANGELOG.md)
|
|
611
|
+
|
|
612
|
+
---
|
|
613
|
+
|
|
614
|
+
## Examples
|
|
615
|
+
|
|
616
|
+
### Example 1: Simple Static Server
|
|
617
|
+
|
|
618
|
+
```javascript
|
|
619
|
+
const Koa = require('koa');
|
|
620
|
+
const koaClassicServer = require('koa-classic-server');
|
|
621
|
+
|
|
622
|
+
const app = new Koa();
|
|
623
|
+
app.use(koaClassicServer(__dirname + '/public'));
|
|
624
|
+
app.listen(3000);
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
### Example 2: Multi-Directory Server
|
|
628
|
+
|
|
629
|
+
```javascript
|
|
630
|
+
const Koa = require('koa');
|
|
631
|
+
const koaClassicServer = require('koa-classic-server');
|
|
632
|
+
|
|
633
|
+
const app = new Koa();
|
|
634
|
+
|
|
635
|
+
// Serve static assets
|
|
636
|
+
app.use(koaClassicServer(__dirname + '/public', {
|
|
637
|
+
urlPrefix: '/static',
|
|
638
|
+
showDirContents: false
|
|
639
|
+
}));
|
|
640
|
+
|
|
641
|
+
// Serve user uploads
|
|
642
|
+
app.use(koaClassicServer(__dirname + '/uploads', {
|
|
643
|
+
urlPrefix: '/files',
|
|
644
|
+
showDirContents: true
|
|
645
|
+
}));
|
|
646
|
+
|
|
647
|
+
app.listen(3000);
|
|
648
|
+
```
|
|
649
|
+
|
|
650
|
+
### Example 3: Development Server with Templates
|
|
651
|
+
|
|
652
|
+
```javascript
|
|
653
|
+
const Koa = require('koa');
|
|
654
|
+
const koaClassicServer = require('koa-classic-server');
|
|
655
|
+
const ejs = require('ejs');
|
|
656
|
+
|
|
657
|
+
const app = new Koa();
|
|
658
|
+
|
|
659
|
+
// Development mode - show directories
|
|
660
|
+
app.use(koaClassicServer(__dirname + '/src', {
|
|
661
|
+
showDirContents: true,
|
|
662
|
+
template: {
|
|
663
|
+
ext: ['ejs'],
|
|
664
|
+
render: async (ctx, next, filePath) => {
|
|
665
|
+
ctx.body = await ejs.renderFile(filePath, {
|
|
666
|
+
dev: true,
|
|
667
|
+
timestamp: Date.now()
|
|
668
|
+
});
|
|
669
|
+
ctx.type = 'text/html';
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
}));
|
|
673
|
+
|
|
674
|
+
app.listen(3000);
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
---
|
|
678
|
+
|
|
679
|
+
## Troubleshooting
|
|
680
|
+
|
|
681
|
+
### Common Issues
|
|
682
|
+
|
|
683
|
+
**Issue: 404 errors for all files**
|
|
684
|
+
|
|
685
|
+
Check that `rootDir` is an absolute path:
|
|
686
|
+
|
|
687
|
+
```javascript
|
|
688
|
+
// โ Wrong (relative path)
|
|
689
|
+
koaClassicServer('./public')
|
|
690
|
+
|
|
691
|
+
// โ
Correct (absolute path)
|
|
692
|
+
koaClassicServer(__dirname + '/public')
|
|
693
|
+
koaClassicServer(path.join(__dirname, 'public'))
|
|
694
|
+
```
|
|
695
|
+
|
|
696
|
+
**Issue: Reserved URLs not working**
|
|
697
|
+
|
|
698
|
+
Reserved URLs only work for first-level directories:
|
|
699
|
+
|
|
700
|
+
```javascript
|
|
701
|
+
urlsReserved: ['/admin'] // โ
Blocks /admin/*
|
|
702
|
+
urlsReserved: ['/admin/users'] // โ Doesn't work (nested)
|
|
703
|
+
```
|
|
704
|
+
|
|
705
|
+
**Issue: Directory sorting not working**
|
|
706
|
+
|
|
707
|
+
Make sure you're accessing directories without query params initially. The sorting is applied when you click headers.
|
|
708
|
+
|
|
709
|
+
**See full troubleshooting:** [DEBUG_REPORT.md](./docs/DEBUG_REPORT.md)
|
|
710
|
+
|
|
711
|
+
---
|
|
305
712
|
|
|
306
713
|
## Contributing
|
|
307
714
|
|
|
308
|
-
Contributions are welcome! Please
|
|
715
|
+
Contributions are welcome! Please:
|
|
716
|
+
|
|
717
|
+
1. Fork the repository
|
|
718
|
+
2. Create a feature branch
|
|
719
|
+
3. Add tests for new functionality
|
|
720
|
+
4. Ensure all tests pass (`npm test`)
|
|
721
|
+
5. Submit a pull request
|
|
722
|
+
|
|
723
|
+
---
|
|
309
724
|
|
|
310
725
|
## Known Limitations
|
|
311
726
|
|
|
312
727
|
- Reserved URLs only work for first-level directories
|
|
728
|
+
- Template rendering is synchronous per request
|
|
313
729
|
|
|
314
730
|
See [DEBUG_REPORT.md](./docs/DEBUG_REPORT.md) for technical details.
|
|
315
731
|
|
|
732
|
+
---
|
|
733
|
+
|
|
316
734
|
## License
|
|
317
735
|
|
|
318
|
-
MIT
|
|
736
|
+
MIT License - see LICENSE file for details
|
|
737
|
+
|
|
738
|
+
---
|
|
319
739
|
|
|
320
740
|
## Author
|
|
321
741
|
|
|
322
742
|
Italo Paesano
|
|
323
743
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
See [CHANGELOG.md](./CHANGELOG.md)
|
|
744
|
+
---
|
|
327
745
|
|
|
328
746
|
## Links
|
|
329
747
|
|
|
330
|
-
- [
|
|
331
|
-
- [
|
|
332
|
-
- [
|
|
333
|
-
- [
|
|
334
|
-
|
|
748
|
+
- **[npm Package](https://www.npmjs.com/package/koa-classic-server)** - Official npm package
|
|
749
|
+
- **[GitHub Repository](https://github.com/italopaesano/koa-classic-server)** - Source code
|
|
750
|
+
- **[Issue Tracker](https://github.com/italopaesano/koa-classic-server/issues)** - Report bugs
|
|
751
|
+
- **[Full Documentation](./docs/DOCUMENTATION.md)** - Complete reference
|
|
752
|
+
|
|
753
|
+
---
|
|
754
|
+
|
|
755
|
+
## Changelog
|
|
756
|
+
|
|
757
|
+
See [CHANGELOG.md](./docs/CHANGELOG.md) for version history.
|
|
335
758
|
|
|
336
759
|
---
|
|
337
760
|
|
|
338
|
-
**โ ๏ธ Security Notice:**
|
|
761
|
+
**โ ๏ธ Security Notice:** Always use the latest version for security updates and bug fixes.
|
package/docs/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,84 @@ All notable changes to koa-classic-server will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.1.3] - 2025-11-25
|
|
9
|
+
|
|
10
|
+
### ๐ง Configuration Changes
|
|
11
|
+
|
|
12
|
+
#### Changed Default Caching Behavior
|
|
13
|
+
- **Change**: `enableCaching` default value changed from `true` to `false`
|
|
14
|
+
- **Rationale**: Better development experience - changes are immediately visible without cache invalidation
|
|
15
|
+
- **Production Impact**: **Users should explicitly set `enableCaching: true` in production environments**
|
|
16
|
+
- **Benefits in Production**:
|
|
17
|
+
- 80-95% bandwidth reduction
|
|
18
|
+
- Faster page loads with 304 Not Modified responses
|
|
19
|
+
- Reduced server load
|
|
20
|
+
- **Code**: `index.cjs:107`
|
|
21
|
+
|
|
22
|
+
### ๐ Documentation Improvements
|
|
23
|
+
|
|
24
|
+
#### Enhanced Caching Documentation
|
|
25
|
+
- Added comprehensive production recommendations in README.md
|
|
26
|
+
- Added inline code comments explaining the default behavior
|
|
27
|
+
- Clear guidance on when to enable caching (development vs production)
|
|
28
|
+
- **Files**: `README.md`, `index.cjs`
|
|
29
|
+
|
|
30
|
+
### โ ๏ธ Migration Notice
|
|
31
|
+
|
|
32
|
+
**IMPORTANT**: If you are upgrading from 2.1.2 or earlier and rely on HTTP caching:
|
|
33
|
+
|
|
34
|
+
```javascript
|
|
35
|
+
// You must now explicitly enable caching in production
|
|
36
|
+
app.use(koaClassicServer(__dirname + '/public', {
|
|
37
|
+
enableCaching: true // โ Add this for production environments
|
|
38
|
+
}));
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
**Development**: No changes needed - the new default (`false`) is better for development.
|
|
42
|
+
|
|
43
|
+
**Production**: Explicitly set `enableCaching: true` to maintain previous behavior and performance benefits.
|
|
44
|
+
|
|
45
|
+
### ๐ฆ Package Changes
|
|
46
|
+
|
|
47
|
+
- **Version**: `2.1.2` โ `2.1.3`
|
|
48
|
+
|
|
49
|
+
---
|
|
50
|
+
|
|
51
|
+
## [2.1.2] - 2025-11-24
|
|
52
|
+
|
|
53
|
+
### ๐จ Features
|
|
54
|
+
|
|
55
|
+
#### Sortable Directory Columns
|
|
56
|
+
- Apache2-like directory listing with clickable column headers
|
|
57
|
+
- Sort by Name, Type, or Size (ascending/descending)
|
|
58
|
+
- Fixed navigation bug after sorting
|
|
59
|
+
|
|
60
|
+
#### File Size Display
|
|
61
|
+
- Human-readable file sizes (B, KB, MB, GB, TB)
|
|
62
|
+
- Proper formatting and precision
|
|
63
|
+
|
|
64
|
+
#### HTTP Caching
|
|
65
|
+
- ETag and Last-Modified headers
|
|
66
|
+
- 304 Not Modified responses
|
|
67
|
+
- 80-95% bandwidth reduction
|
|
68
|
+
|
|
69
|
+
### ๐งช Testing
|
|
70
|
+
- 153 tests passing
|
|
71
|
+
- Comprehensive test coverage
|
|
72
|
+
|
|
73
|
+
---
|
|
74
|
+
|
|
75
|
+
## [2.1.1] - 2025-11-23
|
|
76
|
+
|
|
77
|
+
### ๐ Production Release
|
|
78
|
+
|
|
79
|
+
- Async/await implementation
|
|
80
|
+
- Non-blocking I/O
|
|
81
|
+
- Performance optimizations
|
|
82
|
+
- Flow documentation
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
8
86
|
## [1.2.0] - 2025-11-17
|
|
9
87
|
|
|
10
88
|
### ๐ SECURITY & BUG FIX RELEASE
|
package/index.cjs
CHANGED
|
@@ -45,7 +45,10 @@ module.exports = function koaClassicServer(
|
|
|
45
45
|
ext: [], // File extensions to process with template.render
|
|
46
46
|
},
|
|
47
47
|
cacheMaxAge: 3600, // Cache-Control max-age in seconds (default: 1 hour)
|
|
48
|
-
enableCaching:
|
|
48
|
+
enableCaching: false, // Enable HTTP caching headers (ETag, Last-Modified)
|
|
49
|
+
// NOTE: Default is false for development.
|
|
50
|
+
// In production, it's recommended to set enableCaching: true
|
|
51
|
+
// to reduce bandwidth usage and improve performance.
|
|
49
52
|
}
|
|
50
53
|
*/
|
|
51
54
|
) {
|
|
@@ -97,8 +100,11 @@ module.exports = function koaClassicServer(
|
|
|
97
100
|
options.template.ext = Array.isArray(options.template.ext) ? options.template.ext : [];
|
|
98
101
|
|
|
99
102
|
// OPTIMIZATION: HTTP Caching options
|
|
103
|
+
// NOTE: Default enableCaching is false for development environments.
|
|
104
|
+
// For production deployments, it's strongly recommended to enable caching
|
|
105
|
+
// by setting enableCaching: true to benefit from reduced bandwidth and improved performance.
|
|
100
106
|
options.cacheMaxAge = typeof options.cacheMaxAge === 'number' && options.cacheMaxAge >= 0 ? options.cacheMaxAge : 3600;
|
|
101
|
-
options.enableCaching = typeof options.enableCaching === 'boolean' ? options.enableCaching :
|
|
107
|
+
options.enableCaching = typeof options.enableCaching === 'boolean' ? options.enableCaching : false;
|
|
102
108
|
|
|
103
109
|
return async (ctx, next) => {
|
|
104
110
|
// Check if method is allowed
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koa-classic-server",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.3",
|
|
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": {
|
|
@@ -29,6 +29,10 @@
|
|
|
29
29
|
],
|
|
30
30
|
"author": "Italo Paesano",
|
|
31
31
|
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "https://github.com/italopaesano/koa-classic-server"
|
|
35
|
+
},
|
|
32
36
|
"dependencies": {
|
|
33
37
|
"mime-types": "^2.1.35"
|
|
34
38
|
},
|