laju-server 1.0.1 → 1.0.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.
Files changed (2) hide show
  1. package/index.js +67 -91
  2. package/package.json +4 -5
package/index.js CHANGED
@@ -1,7 +1,8 @@
1
- const HyperExpress = require('hyper-express');
1
+ const http = require('http');
2
2
  const path = require('path');
3
3
  const fs = require('fs');
4
4
  const mime = require('mime-types');
5
+ const os = require('os');
5
6
 
6
7
  function startServer(folderPath, port = 3000) {
7
8
  // Check if folder exists
@@ -16,25 +17,9 @@ function startServer(folderPath, port = 3000) {
16
17
  process.exit(1);
17
18
  }
18
19
 
19
- const server = new HyperExpress.Server({
20
- fast_buffers: true,
21
- max_body_buffer: 64 * 1024, // 64KB buffer for streaming
22
- streaming: {
23
- readable: {
24
- highWaterMark: 64 * 1024, // 64KB chunks
25
- },
26
- writable: {
27
- highWaterMark: 64 * 1024, // 64KB chunks
28
- },
29
- },
30
- });
31
-
32
- // Serve static files
33
- server.get('/*', async (req, res) => {
34
- let requestPath = req.path;
35
-
20
+ const server = http.createServer((req, res) => {
36
21
  // Decode URL
37
- requestPath = decodeURIComponent(requestPath);
22
+ let requestPath = decodeURIComponent(req.url.split('?')[0]);
38
23
 
39
24
  // Remove leading slash
40
25
  if (requestPath.startsWith('/')) {
@@ -51,115 +36,105 @@ function startServer(folderPath, port = 3000) {
51
36
  // Security: prevent directory traversal
52
37
  const resolvedPath = path.resolve(filePath);
53
38
  if (!resolvedPath.startsWith(path.resolve(folderPath))) {
54
- res.status(403).send('Forbidden');
39
+ res.writeHead(403);
40
+ res.end('Forbidden');
55
41
  return;
56
42
  }
57
43
 
58
- try {
59
- // Check if file exists
60
- if (!fs.existsSync(resolvedPath)) {
44
+ // Check if file exists
45
+ fs.stat(resolvedPath, (err, stat) => {
46
+ if (err) {
61
47
  // Try adding index.html if it's a directory
62
48
  const indexPath = path.join(resolvedPath, 'index.html');
63
- if (fs.existsSync(indexPath) && fs.statSync(indexPath).isFile()) {
64
- return serveFile(indexPath, res, req);
65
- }
66
- res.status(404).send('File not found');
49
+ fs.stat(indexPath, (err2, stat2) => {
50
+ if (!err2 && stat2.isFile()) {
51
+ return serveFile(indexPath, stat2, req, res);
52
+ }
53
+ res.writeHead(404);
54
+ res.end('File not found');
55
+ });
67
56
  return;
68
57
  }
69
58
 
70
- const stat = fs.statSync(resolvedPath);
71
-
72
59
  if (stat.isDirectory()) {
73
- // Try serving index.html from directory
74
60
  const indexPath = path.join(resolvedPath, 'index.html');
75
- if (fs.existsSync(indexPath)) {
76
- return serveFile(indexPath, res, req);
77
- }
78
- res.status(404).send('File not found');
61
+ fs.stat(indexPath, (err2, stat2) => {
62
+ if (!err2 && stat2.isFile()) {
63
+ return serveFile(indexPath, stat2, req, res);
64
+ }
65
+ res.writeHead(404);
66
+ res.end('File not found');
67
+ });
79
68
  return;
80
69
  }
81
70
 
82
- return serveFile(resolvedPath, res, req);
83
- } catch (err) {
84
- console.error('Error:', err.message);
85
- res.status(500).send('Internal Server Error');
86
- }
71
+ serveFile(resolvedPath, stat, req, res);
72
+ });
87
73
  });
88
74
 
89
- function serveFile(filePath, res, req) {
75
+ function serveFile(filePath, stat, req, res) {
90
76
  const mimeType = mime.lookup(filePath) || 'application/octet-stream';
91
- const stat = fs.statSync(filePath);
92
77
  const fileSize = stat.size;
93
-
94
- const range = req.headers['range'];
95
-
96
- // Use larger buffer for big files (64KB chunks)
97
- const highWaterMark = 64 * 1024;
78
+ const range = req.headers.range;
98
79
 
99
80
  if (range) {
100
- // Handle range requests for video streaming / resume download
101
81
  const parts = range.replace(/bytes=/, '').split('-');
102
82
  const start = parseInt(parts[0], 10);
103
- // Limit chunk size to 10MB per request for stability
104
- const maxChunk = 10 * 1024 * 1024;
105
- let end = parts[1] ? parseInt(parts[1], 10) : Math.min(start + maxChunk, fileSize - 1);
106
-
107
- // Ensure end doesn't exceed file size
108
- if (end >= fileSize) end = fileSize - 1;
109
-
83
+ const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
110
84
  const chunkSize = end - start + 1;
111
85
 
112
- res.status(206);
113
- res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);
114
- res.setHeader('Accept-Ranges', 'bytes');
115
- res.setHeader('Content-Length', chunkSize);
116
- res.setHeader('Content-Type', mimeType);
117
- res.setHeader('Connection', 'keep-alive');
86
+ res.writeHead(206, {
87
+ 'Content-Range': `bytes ${start}-${end}/${fileSize}`,
88
+ 'Accept-Ranges': 'bytes',
89
+ 'Content-Length': chunkSize,
90
+ 'Content-Type': mimeType,
91
+ });
118
92
 
119
- const stream = fs.createReadStream(filePath, { start, end, highWaterMark });
93
+ const stream = fs.createReadStream(filePath, { start, end });
94
+ stream.pipe(res);
120
95
 
121
96
  stream.on('error', (err) => {
122
97
  console.error('Stream error:', err.message);
123
- if (!res.headersSent) {
124
- res.status(500).send('Stream error');
125
- }
98
+ res.end();
126
99
  });
127
100
 
128
- res.stream(stream);
101
+ req.on('close', () => {
102
+ stream.destroy();
103
+ });
129
104
  } else {
130
- // For large files without range, suggest client to use range requests
131
- res.setHeader('Content-Length', fileSize);
132
- res.setHeader('Content-Type', mimeType);
133
- res.setHeader('Accept-Ranges', 'bytes');
134
- res.setHeader('Connection', 'keep-alive');
105
+ res.writeHead(200, {
106
+ 'Content-Length': fileSize,
107
+ 'Content-Type': mimeType,
108
+ 'Accept-Ranges': 'bytes',
109
+ });
135
110
 
136
- const stream = fs.createReadStream(filePath, { highWaterMark });
111
+ const stream = fs.createReadStream(filePath);
112
+ stream.pipe(res);
137
113
 
138
114
  stream.on('error', (err) => {
139
115
  console.error('Stream error:', err.message);
140
- if (!res.headersSent) {
141
- res.status(500).send('Stream error');
142
- }
116
+ res.end();
143
117
  });
144
118
 
145
- res.stream(stream);
119
+ req.on('close', () => {
120
+ stream.destroy();
121
+ });
146
122
  }
147
123
  }
148
124
 
149
- server.listen(port, '0.0.0.0')
150
- .then(() => {
151
- const networkInterfaces = require('os').networkInterfaces();
152
- const addresses = [];
153
-
154
- for (const name of Object.keys(networkInterfaces)) {
155
- for (const net of networkInterfaces[name]) {
156
- if (net.family === 'IPv4' && !net.internal) {
157
- addresses.push(net.address);
158
- }
125
+ server.listen(port, '0.0.0.0', () => {
126
+ const networkInterfaces = os.networkInterfaces();
127
+ const addresses = [];
128
+
129
+ for (const name of Object.keys(networkInterfaces)) {
130
+ for (const net of networkInterfaces[name]) {
131
+ if (net.family === 'IPv4' && !net.internal) {
132
+ addresses.push(net.address);
159
133
  }
160
134
  }
135
+ }
161
136
 
162
- console.log(`
137
+ console.log(`
163
138
  🚀 Laju Server berjalan!
164
139
 
165
140
  📁 Folder: ${folderPath}
@@ -168,11 +143,12 @@ function startServer(folderPath, port = 3000) {
168
143
 
169
144
  Tekan Ctrl+C untuk berhenti
170
145
  `);
171
- })
172
- .catch((err) => {
173
- console.error('❌ Gagal menjalankan server:', err.message);
174
- process.exit(1);
175
- });
146
+ });
147
+
148
+ server.on('error', (err) => {
149
+ console.error('❌ Gagal menjalankan server:', err.message);
150
+ process.exit(1);
151
+ });
176
152
  }
177
153
 
178
154
  module.exports = { startServer };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "laju-server",
3
- "version": "1.0.1",
4
- "description": "Instant static file server using hyper-express",
3
+ "version": "1.0.3",
4
+ "description": "Instant static file server - supports large files up to 100GB+",
5
5
  "main": "index.js",
6
6
  "bin": {
7
7
  "laju-server": "./bin/cli.js"
@@ -12,14 +12,13 @@
12
12
  "keywords": [
13
13
  "static",
14
14
  "server",
15
- "hyper-express",
16
15
  "file-server",
17
- "cli"
16
+ "cli",
17
+ "large-files"
18
18
  ],
19
19
  "author": "",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "hyper-express": "^6.17.3",
23
22
  "mime-types": "^2.1.35"
24
23
  }
25
24
  }