laju-server 1.0.0 → 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 +74 -60
  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,14 +17,9 @@ function startServer(folderPath, port = 3000) {
16
17
  process.exit(1);
17
18
  }
18
19
 
19
- const server = new HyperExpress.Server();
20
-
21
- // Serve static files
22
- server.get('/*', async (req, res) => {
23
- let requestPath = req.path;
24
-
20
+ const server = http.createServer((req, res) => {
25
21
  // Decode URL
26
- requestPath = decodeURIComponent(requestPath);
22
+ let requestPath = decodeURIComponent(req.url.split('?')[0]);
27
23
 
28
24
  // Remove leading slash
29
25
  if (requestPath.startsWith('/')) {
@@ -40,88 +36,105 @@ function startServer(folderPath, port = 3000) {
40
36
  // Security: prevent directory traversal
41
37
  const resolvedPath = path.resolve(filePath);
42
38
  if (!resolvedPath.startsWith(path.resolve(folderPath))) {
43
- res.status(403).send('Forbidden');
39
+ res.writeHead(403);
40
+ res.end('Forbidden');
44
41
  return;
45
42
  }
46
43
 
47
- try {
48
- // Check if file exists
49
- if (!fs.existsSync(resolvedPath)) {
44
+ // Check if file exists
45
+ fs.stat(resolvedPath, (err, stat) => {
46
+ if (err) {
50
47
  // Try adding index.html if it's a directory
51
48
  const indexPath = path.join(resolvedPath, 'index.html');
52
- if (fs.existsSync(indexPath) && fs.statSync(indexPath).isFile()) {
53
- return serveFile(indexPath, res, req);
54
- }
55
- 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
+ });
56
56
  return;
57
57
  }
58
58
 
59
- const stat = fs.statSync(resolvedPath);
60
-
61
59
  if (stat.isDirectory()) {
62
- // Try serving index.html from directory
63
60
  const indexPath = path.join(resolvedPath, 'index.html');
64
- if (fs.existsSync(indexPath)) {
65
- return serveFile(indexPath, res, req);
66
- }
67
- 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
+ });
68
68
  return;
69
69
  }
70
70
 
71
- return serveFile(resolvedPath, res, req);
72
- } catch (err) {
73
- console.error('Error:', err.message);
74
- res.status(500).send('Internal Server Error');
75
- }
71
+ serveFile(resolvedPath, stat, req, res);
72
+ });
76
73
  });
77
74
 
78
- function serveFile(filePath, res, req) {
75
+ function serveFile(filePath, stat, req, res) {
79
76
  const mimeType = mime.lookup(filePath) || 'application/octet-stream';
80
- const stat = fs.statSync(filePath);
81
77
  const fileSize = stat.size;
82
-
83
- const range = req.headers['range'];
78
+ const range = req.headers.range;
84
79
 
85
80
  if (range) {
86
- // Handle range requests for video streaming / resume download
87
81
  const parts = range.replace(/bytes=/, '').split('-');
88
82
  const start = parseInt(parts[0], 10);
89
83
  const end = parts[1] ? parseInt(parts[1], 10) : fileSize - 1;
90
84
  const chunkSize = end - start + 1;
91
85
 
92
- res.status(206);
93
- res.setHeader('Content-Range', `bytes ${start}-${end}/${fileSize}`);
94
- res.setHeader('Accept-Ranges', 'bytes');
95
- res.setHeader('Content-Length', chunkSize);
96
- res.setHeader('Content-Type', mimeType);
86
+ res.writeHead(206, {
87
+ 'Content-Range': `bytes ${start}-${end}/${fileSize}`,
88
+ 'Accept-Ranges': 'bytes',
89
+ 'Content-Length': chunkSize,
90
+ 'Content-Type': mimeType,
91
+ });
97
92
 
98
93
  const stream = fs.createReadStream(filePath, { start, end });
99
- res.stream(stream);
94
+ stream.pipe(res);
95
+
96
+ stream.on('error', (err) => {
97
+ console.error('Stream error:', err.message);
98
+ res.end();
99
+ });
100
+
101
+ req.on('close', () => {
102
+ stream.destroy();
103
+ });
100
104
  } else {
101
- // Stream full file
102
- res.setHeader('Content-Length', fileSize);
103
- res.setHeader('Content-Type', mimeType);
104
- res.setHeader('Accept-Ranges', 'bytes');
105
+ res.writeHead(200, {
106
+ 'Content-Length': fileSize,
107
+ 'Content-Type': mimeType,
108
+ 'Accept-Ranges': 'bytes',
109
+ });
105
110
 
106
111
  const stream = fs.createReadStream(filePath);
107
- res.stream(stream);
112
+ stream.pipe(res);
113
+
114
+ stream.on('error', (err) => {
115
+ console.error('Stream error:', err.message);
116
+ res.end();
117
+ });
118
+
119
+ req.on('close', () => {
120
+ stream.destroy();
121
+ });
108
122
  }
109
123
  }
110
124
 
111
- server.listen(port, '0.0.0.0')
112
- .then(() => {
113
- const networkInterfaces = require('os').networkInterfaces();
114
- const addresses = [];
115
-
116
- for (const name of Object.keys(networkInterfaces)) {
117
- for (const net of networkInterfaces[name]) {
118
- if (net.family === 'IPv4' && !net.internal) {
119
- addresses.push(net.address);
120
- }
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);
121
133
  }
122
134
  }
135
+ }
123
136
 
124
- console.log(`
137
+ console.log(`
125
138
  🚀 Laju Server berjalan!
126
139
 
127
140
  📁 Folder: ${folderPath}
@@ -130,11 +143,12 @@ function startServer(folderPath, port = 3000) {
130
143
 
131
144
  Tekan Ctrl+C untuk berhenti
132
145
  `);
133
- })
134
- .catch((err) => {
135
- console.error('❌ Gagal menjalankan server:', err.message);
136
- process.exit(1);
137
- });
146
+ });
147
+
148
+ server.on('error', (err) => {
149
+ console.error('❌ Gagal menjalankan server:', err.message);
150
+ process.exit(1);
151
+ });
138
152
  }
139
153
 
140
154
  module.exports = { startServer };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "laju-server",
3
- "version": "1.0.0",
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
  }