servez 1.14.1 → 2.0.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 +4 -0
- package/bin/servez +127 -141
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -12,6 +12,10 @@
|
|
|
12
12
|
|
|
13
13
|
# Installing globally:
|
|
14
14
|
|
|
15
|
+
!!!Note!!!: you need to install [node.js](https://nodejs.org).
|
|
16
|
+
I recommend installing node via [nvm](https://github.com/nvm-sh/nvm)(mac/linux)
|
|
17
|
+
or [nvm-windows](https://github.com/coreybutler/nvm-windows)(windows)
|
|
18
|
+
|
|
15
19
|
Installation via `npm`:
|
|
16
20
|
|
|
17
21
|
npm install servez -g
|
package/bin/servez
CHANGED
|
@@ -2,7 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
"use strict";
|
|
4
4
|
|
|
5
|
-
const
|
|
5
|
+
const { program } = require('commander');
|
|
6
|
+
const pkg = require('../package.json');
|
|
6
7
|
const colorSupport = require('color-support') || {};
|
|
7
8
|
const c = require('ansi-colors');
|
|
8
9
|
c.enabled = colorSupport.hasBasic;
|
|
@@ -19,153 +20,138 @@ const log = {
|
|
|
19
20
|
},
|
|
20
21
|
};
|
|
21
22
|
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const line = [];
|
|
30
|
-
for (let x = -2; x < size; ++x) {
|
|
31
|
-
line.push(c[qr.getModule(x, y) ? 'bgBlack' : 'bgWhite'](' '));
|
|
32
|
-
}
|
|
33
|
-
lines.push(line.join(''));
|
|
23
|
+
const fixedParseInt = v => parseInt(v);
|
|
24
|
+
const parseHeader = (v, oldV) => {
|
|
25
|
+
console.log('v:', `'${v}'`);
|
|
26
|
+
console.log('oldV:', `'${JSON.stringify(oldV)}'`);
|
|
27
|
+
const m = /^(.*?):(.*?)$/.exec(v);
|
|
28
|
+
if (!m) {
|
|
29
|
+
throw new Error('bad header argument: format is --header=<header>:<value>');
|
|
34
30
|
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
const optionSpec = {
|
|
39
|
-
options: [
|
|
40
|
-
{ option: 'help', alias: 'h', type: 'Boolean', description: 'displays help' },
|
|
41
|
-
{ option: 'port', alias: 'p', type: 'Int', description: 'port', default: '8080' },
|
|
42
|
-
{ option: 'version', type: 'Boolean', description: 'print version' },
|
|
43
|
-
{ option: 'scan', type: 'Boolean', description: 'scan for open port', default: 'true', },
|
|
44
|
-
{ option: 'qr', type: 'Boolean', description: 'print QR Code for root url' },
|
|
45
|
-
{ option: 'dirs', type: 'Boolean', description: 'show directory listing', default: 'true', },
|
|
46
|
-
{ option: 'cors', type: 'Boolean', description: 'send CORS headers', default: 'true', },
|
|
47
|
-
{ option: 'local', type: 'Boolean', description: 'local machine only', default: 'false', },
|
|
48
|
-
{ option: 'index', type: 'Boolean', description: 'serve index.html for directories', default: 'true', },
|
|
49
|
-
{ option: 'extensions', type: '[String]', description: 'extensions to try if path does not exist', default: '["html"]', },
|
|
50
|
-
{ option: 'unity-hack', type: 'Boolean', description: 'ignore .gz and .br when computing content type', default: 'true', },
|
|
51
|
-
{ option: 'shared-array-buffers', type: 'Boolean', description: "include headers 'Cross-Origin-Opener-Policy': 'same-origin' and 'Cross-Origin-Embedder-Policy': 'require-corp'", default: 'false', },
|
|
52
|
-
{ option: 'header', type: 'Object', description: 'extra headers to include eg --header=Content-Language:de-DE', mergeRepeatedObjects: true},
|
|
53
|
-
{ option: 'gzip', type: 'Boolean', description: 'serve .gz files if they exist', default: 'false', },
|
|
54
|
-
{ option: 'brotli', type: 'Boolean', description: 'serve .br files if they exist', default: 'false', },
|
|
55
|
-
{ option: 'robots', type: 'Boolean', description: 'serve a robots.txt if one does not exist', default: 'true', },
|
|
56
|
-
{ option: 'hidden', type: 'Boolean', description: 'show hidden dotfiles', default: 'false', },
|
|
57
|
-
{ option: 'username', type: 'String', description: 'username for basic auth' },
|
|
58
|
-
{ option: 'password', type: 'String', description: 'password for basic auth' },
|
|
59
|
-
{ option: 'ssl', alias: 'S', type: 'Boolean', description: 'enable https (will use fake cert if not specified)', },
|
|
60
|
-
{ option: 'cert', alias: 'C', type: 'String', description: 'Path to ssl cert file', },
|
|
61
|
-
{ option: 'key', alias: 'K', type: 'String', description: 'Path to ssl key file', },
|
|
62
|
-
],
|
|
63
|
-
prepend: `Usage: servez [options] [path-to-serve]`,
|
|
64
|
-
helpStyle: {
|
|
65
|
-
typeSeparator: '=',
|
|
66
|
-
descriptionSeparator: ' : ',
|
|
67
|
-
initialIndent: 4,
|
|
68
|
-
},
|
|
31
|
+
const newV = {...oldV};
|
|
32
|
+
newV[m[1]] = m[2];
|
|
33
|
+
return newV;
|
|
69
34
|
};
|
|
70
|
-
/* eslint-enable object-curly-newline */
|
|
71
|
-
const optionator = makeOptions(optionSpec);
|
|
72
|
-
|
|
73
|
-
let args;
|
|
74
|
-
try {
|
|
75
|
-
args = optionator.parse(process.argv);
|
|
76
|
-
} catch (e) {
|
|
77
|
-
log.error(e);
|
|
78
|
-
printHelp();
|
|
79
|
-
}
|
|
80
35
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
36
|
+
program
|
|
37
|
+
.name('servez')
|
|
38
|
+
.version(pkg.version)
|
|
39
|
+
.usage('[options] [path-to-serve]')
|
|
40
|
+
.argument('[path-to-serve]', 'path to serve')
|
|
41
|
+
.option('-p, --port <port>', 'port', fixedParseInt, 8080)
|
|
42
|
+
.option('--no-scan', 'do not scan for open port')
|
|
43
|
+
.option('--qr', 'print QR Code for root url')
|
|
44
|
+
.option('--no-dirs', 'do not show directory listing')
|
|
45
|
+
.option('--no-cors', 'do not send CORS headers')
|
|
46
|
+
.option('--local', 'local machine only')
|
|
47
|
+
.option('--no-index', 'do not serve index.html for directories')
|
|
48
|
+
.option('--extensions <extensions...>','extensions to try if path does not exist', ['html'])
|
|
49
|
+
.option('--no-unity-hack', 'do not ignore .gz and .br when computing content type')
|
|
50
|
+
.option('--shared-array-buffers', "include headers 'Cross-Origin-Opener-Policy': 'same-origin' and 'Cross-Origin-Embedder-Policy': 'require-corp'", false)
|
|
51
|
+
.option('--header <header>', 'extra headers to include eg --header=Content-Language:de-DE', parseHeader, {})
|
|
52
|
+
.option('--gzip', 'serve .gz files if they exist', false)
|
|
53
|
+
.option('--brotli', 'serve .br files if they exist', false)
|
|
54
|
+
.option('--no-robots', 'do not serve a robots.txt if one does not exist', true)
|
|
55
|
+
.option('--hidden', 'show hidden dotfiles', false)
|
|
56
|
+
.option('--username <username>', 'username for basic auth')
|
|
57
|
+
.option('--password <password>', 'password for basic auth')
|
|
58
|
+
.option('-S, --ssl', 'enable https (will use fake cert if not specified)', false)
|
|
59
|
+
.option('-C, --cert <cert>', 'Path to ssl cert file')
|
|
60
|
+
.option('-K, --key <key>', 'Path to ssl key file')
|
|
61
|
+
.action(main);
|
|
62
|
+
|
|
63
|
+
program.showHelpAfterError('(add --help for additional information)');
|
|
64
|
+
program.parse();
|
|
65
|
+
|
|
66
|
+
function main(pathToServe, args) {
|
|
67
|
+
args.headers = args.header;
|
|
68
|
+
delete args.header;
|
|
69
|
+
|
|
70
|
+
const fs = require('fs');
|
|
71
|
+
const path = require('path');
|
|
72
|
+
const {QrCode, Ecc} = require('../lib/qrcodegen');
|
|
73
|
+
const hosts = [];
|
|
74
|
+
|
|
75
|
+
function genQRCode(s) {
|
|
76
|
+
const qr = QrCode.encodeText(s, Ecc.MEDIUM);
|
|
77
|
+
const size = qr.size + 2;
|
|
78
|
+
|
|
79
|
+
const lines = [];
|
|
80
|
+
for (let y = -2; y < size; ++y) {
|
|
81
|
+
const line = [];
|
|
82
|
+
for (let x = -2; x < size; ++x) {
|
|
83
|
+
line.push(c[qr.getModule(x, y) ? 'bgBlack' : 'bgWhite'](' '));
|
|
84
|
+
}
|
|
85
|
+
lines.push(line.join(''));
|
|
86
|
+
}
|
|
87
|
+
return lines.join('\n');
|
|
117
88
|
}
|
|
118
|
-
}
|
|
119
89
|
|
|
120
|
-
process.
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
},
|
|
127
|
-
error(args) {
|
|
128
|
-
console.error(c.red(args.join(' ')));
|
|
129
|
-
},
|
|
130
|
-
host(args) {
|
|
131
|
-
const localRE = /\D0\.0\.0\.0.\D|\D127\.0\.0\.|\Wlocalhost\W/
|
|
132
|
-
const [data] = args;
|
|
133
|
-
const {root} = data;
|
|
134
|
-
if (!localRE.test(root)) {
|
|
135
|
-
hosts.push(root);
|
|
90
|
+
const root = path.resolve(pathToServe || process.cwd());
|
|
91
|
+
try {
|
|
92
|
+
const stat = fs.statSync(root);
|
|
93
|
+
if (!stat.isDirectory()) {
|
|
94
|
+
log.error(`'${root}' is not a directory`);
|
|
95
|
+
process.exit(1); // eslint-disable-line
|
|
136
96
|
}
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
log.info('');
|
|
144
|
-
}
|
|
97
|
+
} catch (e) {
|
|
98
|
+
if (e.code === 'ENOENT') {
|
|
99
|
+
log.warn(c.bold.yellow(`!!!!!!!!!!!!!!!\n\n WARNING: '${root}' does not exist!\n\n!!!!!!!!!!!!!!!`));
|
|
100
|
+
} else {
|
|
101
|
+
log.error(e, e.stack);
|
|
102
|
+
process.exit(1); // eslint-disable-line
|
|
145
103
|
}
|
|
146
|
-
log.info('press CTRL-C to stop the server.');
|
|
147
|
-
},
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
const {Worker} = require('worker_threads');
|
|
151
|
-
const worker = new Worker(path.join(__dirname, '..', 'src', 'server-worker.js'), {
|
|
152
|
-
workerData: {
|
|
153
|
-
root,
|
|
154
|
-
args,
|
|
155
|
-
useColors: colorSupport.hasBasic,
|
|
156
|
-
},
|
|
157
|
-
});
|
|
158
|
-
worker.on('message', (msg) => {
|
|
159
|
-
const cmd = msg.cmd;
|
|
160
|
-
const fn = commands[cmd];
|
|
161
|
-
if (!fn) {
|
|
162
|
-
throw new Error(`unknown cmd: ${cmd}`);
|
|
163
104
|
}
|
|
164
|
-
fn(msg.data);
|
|
165
|
-
});
|
|
166
105
|
|
|
167
|
-
process.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
106
|
+
process.stdin.destroy(); // this allows control-c to not print "Terminate Batch?"
|
|
107
|
+
process.title = `servez ${root.split(/\\|\//g).slice(-3).join(path.sep)}`;
|
|
108
|
+
|
|
109
|
+
const commands = {
|
|
110
|
+
log(args) {
|
|
111
|
+
console.log(...args);
|
|
112
|
+
},
|
|
113
|
+
error(args) {
|
|
114
|
+
console.error(c.red(args.join(' ')));
|
|
115
|
+
},
|
|
116
|
+
host(args) {
|
|
117
|
+
const localRE = /\D0\.0\.0\.0.\D|\D127\.0\.0\.|\Wlocalhost\W/
|
|
118
|
+
const [data] = args;
|
|
119
|
+
const {root} = data;
|
|
120
|
+
if (!localRE.test(root)) {
|
|
121
|
+
hosts.push(root);
|
|
122
|
+
}
|
|
123
|
+
},
|
|
124
|
+
start(data) {
|
|
125
|
+
if (args.qr) {
|
|
126
|
+
for (const host of hosts) {
|
|
127
|
+
log.info(`--------------\nQR code for: ${host}`);
|
|
128
|
+
log.info(genQRCode(host));
|
|
129
|
+
log.info('');
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
log.info('press CTRL-C to stop the server.');
|
|
133
|
+
},
|
|
134
|
+
};
|
|
135
|
+
|
|
136
|
+
const {Worker} = require('worker_threads');
|
|
137
|
+
const worker = new Worker(path.join(__dirname, '..', 'src', 'server-worker.js'), {
|
|
138
|
+
workerData: {
|
|
139
|
+
root,
|
|
140
|
+
args,
|
|
141
|
+
useColors: colorSupport.hasBasic,
|
|
142
|
+
},
|
|
143
|
+
});
|
|
144
|
+
worker.on('message', (msg) => {
|
|
145
|
+
const cmd = msg.cmd;
|
|
146
|
+
const fn = commands[cmd];
|
|
147
|
+
if (!fn) {
|
|
148
|
+
throw new Error(`unknown cmd: ${cmd}`);
|
|
149
|
+
}
|
|
150
|
+
fn(msg.data);
|
|
151
|
+
});
|
|
171
152
|
|
|
153
|
+
process.on('SIGINT', function () {
|
|
154
|
+
console.log(c.red('servez stopped.'));
|
|
155
|
+
process.exit(0);
|
|
156
|
+
});
|
|
157
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "servez",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"description": "A simple command line server to replace http-server",
|
|
5
5
|
"scripts": {
|
|
6
6
|
"start": "node ./bin/servez"
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
"dependencies": {
|
|
26
26
|
"ansi-colors": "^4.1.1",
|
|
27
27
|
"color-support": "^1.1.3",
|
|
28
|
-
"
|
|
28
|
+
"commander": "^11.0.0",
|
|
29
29
|
"servez-lib": "^2.6.0"
|
|
30
30
|
},
|
|
31
31
|
"bin": {
|