Static file serving middleware for Koa.js applications with compression, caching, and security features.
npx @tessl/cli install tessl/npm-koa-send@5.0.00
# koa-send
1
2
koa-send is a static file serving middleware for Koa.js applications that provides secure, efficient delivery of static assets to web clients. It offers comprehensive file serving capabilities including automatic compression support (gzip and brotli), configurable browser caching, path normalization and security protections against directory traversal attacks, and flexible content type detection.
3
4
## Package Information
5
6
- **Package Name**: koa-send
7
- **Package Type**: npm
8
- **Language**: JavaScript (Node.js)
9
- **Installation**: `npm install koa-send`
10
11
## Core Imports
12
13
```javascript
14
const send = require('koa-send');
15
```
16
17
For ES modules:
18
19
```javascript
20
import send from 'koa-send';
21
```
22
23
## Basic Usage
24
25
```javascript
26
const send = require('koa-send');
27
const Koa = require('koa');
28
const app = new Koa();
29
30
// Basic file serving
31
app.use(async (ctx) => {
32
if (ctx.path === '/') {
33
ctx.body = 'Try GET /package.json';
34
return;
35
}
36
await send(ctx, ctx.path);
37
});
38
39
// Serve from a root directory
40
app.use(async (ctx) => {
41
await send(ctx, ctx.path, { root: __dirname + '/public' });
42
});
43
44
app.listen(3000);
45
```
46
47
## Capabilities
48
49
### Static File Serving
50
51
Serves static files with comprehensive security and performance features.
52
53
```javascript { .api }
54
/**
55
* Send static file with given options to Koa context
56
* @param {Context} ctx - Koa context object (required)
57
* @param {string} path - File path to serve (required)
58
* @param {SendOptions} opts - Options object (optional)
59
* @returns {Promise<string>} - Resolved file path that was served
60
* @throws {Error} 400 if path decode fails
61
* @throws {Error} 404 if file not found
62
* @throws {Error} 500 for other file system errors
63
* @throws {TypeError} if setHeaders is not a function
64
*/
65
async function send(ctx, path, opts = {});
66
```
67
68
**Usage Examples:**
69
70
```javascript
71
// Basic usage
72
await send(ctx, 'path/to/file.txt');
73
74
// With root directory
75
await send(ctx, ctx.path, { root: '/public' });
76
77
// With compression and caching
78
await send(ctx, ctx.path, {
79
root: __dirname + '/static',
80
maxage: 86400000, // 24 hours
81
gzip: true,
82
brotli: true,
83
immutable: true
84
});
85
86
// With custom headers
87
await send(ctx, ctx.path, {
88
root: '/assets',
89
setHeaders: (res, path, stats) => {
90
res.setHeader('X-Served-By', 'koa-send');
91
}
92
});
93
```
94
95
## Options
96
97
### SendOptions Interface
98
99
```javascript { .api }
100
/**
101
* Configuration options for the send function
102
*/
103
interface SendOptions {
104
/** Root directory to restrict file access (defaults to '') */
105
root?: string;
106
/** Browser cache max-age in milliseconds (defaults to 0) */
107
maxage?: number;
108
/** Alias for maxage (defaults to 0) */
109
maxAge?: number;
110
/** Mark resource as immutable for caching (defaults to false) */
111
immutable?: boolean;
112
/** Allow transfer of hidden files (defaults to false) */
113
hidden?: boolean;
114
/** Name of index file for directories (defaults to undefined) */
115
index?: string;
116
/** Format path for directory handling (defaults to true) */
117
format?: boolean;
118
/** File extensions to try when no extension provided (defaults to false) */
119
extensions?: Array<string> | false;
120
/** Enable brotli compression support (defaults to true) */
121
brotli?: boolean;
122
/** Enable gzip compression support (defaults to true) */
123
gzip?: boolean;
124
/** Custom headers function (defaults to undefined) */
125
setHeaders?: (res: ServerResponse, path: string, stats: Stats) => void;
126
}
127
```
128
129
### Option Details
130
131
#### Root Directory (`root`)
132
133
Specifies the root directory from which to serve files. The path is resolved and normalized for security.
134
135
```javascript
136
// Serve files from public directory
137
await send(ctx, ctx.path, { root: __dirname + '/public' });
138
139
// Serve specific file without user input
140
await send(ctx, 'path/to/my.js');
141
```
142
143
#### Caching Options (`maxage`, `immutable`)
144
145
Control browser caching behavior:
146
147
```javascript
148
// Cache for 24 hours
149
await send(ctx, ctx.path, {
150
maxage: 86400000,
151
immutable: true // Resource never changes
152
});
153
```
154
155
#### Compression (`gzip`, `brotli`)
156
157
Automatic compression based on client support:
158
159
```javascript
160
// Enable both compression methods (default)
161
await send(ctx, ctx.path, {
162
gzip: true,
163
brotli: true
164
});
165
166
// Disable compression
167
await send(ctx, ctx.path, {
168
gzip: false,
169
brotli: false
170
});
171
```
172
173
#### Extension Matching (`extensions`)
174
175
Try multiple extensions for extensionless requests:
176
177
```javascript
178
// Try .html, .js extensions
179
await send(ctx, ctx.path, {
180
extensions: ['html', 'js']
181
});
182
183
// Also works with dots
184
await send(ctx, ctx.path, {
185
extensions: ['.html', '.js']
186
});
187
```
188
189
#### Index Files (`index`)
190
191
Serve index files for directory requests:
192
193
```javascript
194
// Serve index.html for directory requests
195
await send(ctx, ctx.path, {
196
index: 'index.html',
197
format: true // Handle trailing slashes
198
});
199
```
200
201
#### Custom Headers (`setHeaders`)
202
203
Set custom response headers:
204
205
```javascript
206
await send(ctx, ctx.path, {
207
setHeaders: (res, path, stats) => {
208
// Only modify Cache-Control or Last-Modified here
209
// Other headers should be set before calling send()
210
if (path.endsWith('.js')) {
211
res.setHeader('Cache-Control', 'max-age=31536000, immutable');
212
}
213
}
214
});
215
```
216
217
## Security Features
218
219
### Path Traversal Protection
220
221
koa-send automatically protects against directory traversal attacks:
222
223
- Paths are normalized and resolved safely
224
- Parent directory references (`..`) are handled securely
225
- The `resolve-path` library provides additional security
226
227
### Hidden File Protection
228
229
By default, hidden files (starting with `.`) are not served:
230
231
```javascript
232
// Allow hidden files (use with caution)
233
await send(ctx, ctx.path, { hidden: true });
234
```
235
236
## Error Handling
237
238
The send function throws specific HTTP errors:
239
240
- **400**: Failed to decode the requested path
241
- **404**: File not found, name too long, or not a directory
242
- **500**: Other file system errors
243
- **TypeError**: Invalid `setHeaders` option (not a function)
244
245
```javascript
246
app.use(async (ctx, next) => {
247
try {
248
await send(ctx, ctx.path, { root: '/public' });
249
} catch (err) {
250
if (err.status === 404) {
251
ctx.body = 'File not found';
252
} else {
253
throw err;
254
}
255
}
256
});
257
```
258
259
## Performance Features
260
261
### Automatic Compression
262
263
Files are automatically compressed when:
264
265
- Client supports gzip or brotli encoding
266
- Corresponding compressed file exists (`.gz` or `.br`)
267
- Compression options are enabled (default)
268
269
### Efficient Streaming
270
271
Files are streamed directly to the client using Node.js streams:
272
273
- No memory buffering of large files
274
- Efficient for serving large static assets
275
- Proper Content-Length headers
276
277
### Smart Caching
278
279
Configurable browser caching with:
280
281
- `max-age` directive for cache duration
282
- `immutable` directive for permanent caching
283
- Automatic `Last-Modified` headers
284
- Conditional request support
285
286
## Types
287
288
```javascript { .api }
289
/**
290
* Node.js ServerResponse object
291
*/
292
interface ServerResponse {
293
setHeader(name: string, value: string): void;
294
removeHeader(name: string): void;
295
}
296
297
/**
298
* Node.js fs.Stats object
299
*/
300
interface Stats {
301
size: number;
302
mtime: Date;
303
isDirectory(): boolean;
304
}
305
306
/**
307
* Koa Context object (subset of properties used by send)
308
*/
309
interface Context {
310
path: string;
311
res: ServerResponse;
312
response: {
313
get(field: string): string;
314
};
315
body?: any;
316
type?: string;
317
set(field: string, val: string): void;
318
throw(status: number, message?: string): void;
319
acceptsEncodings(...encodings: string[]): string | false;
320
}
321
```