wsnipz 1.0.0 → 1.1.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/dist/banner.js +2 -2
- package/dist/discord.js +7 -8
- package/dist/index.js +36 -9
- package/dist/mouse.js +66 -0
- package/dist/prompts.js +56 -56
- package/dist/ui.js +7 -7
- package/dist/updater.js +97 -0
- package/dist/version.js +5 -0
- package/package.json +1 -1
package/dist/banner.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.printBanner = printBanner;
|
|
|
7
7
|
const figlet_1 = __importDefault(require("figlet"));
|
|
8
8
|
const chalk_1 = __importDefault(require("chalk"));
|
|
9
9
|
const ui_1 = require("./ui");
|
|
10
|
-
const
|
|
10
|
+
const version_1 = require("./version");
|
|
11
11
|
function printBanner() {
|
|
12
12
|
const art = figlet_1.default.textSync('WSniper', {
|
|
13
13
|
font: 'Standard',
|
|
@@ -20,6 +20,6 @@ function printBanner() {
|
|
|
20
20
|
const line = chalk_1.default.gray('─'.repeat(tag.length));
|
|
21
21
|
console.log(chalk_1.default.gray(tag));
|
|
22
22
|
console.log(line);
|
|
23
|
-
console.log(chalk_1.default.gray(` v${VERSION} • proxies
|
|
23
|
+
console.log(chalk_1.default.gray(` v${version_1.VERSION} • rotating proxies • interactive mode`));
|
|
24
24
|
console.log();
|
|
25
25
|
}
|
package/dist/discord.js
CHANGED
|
@@ -33,7 +33,7 @@ async function checkUsername(username, token, pool) {
|
|
|
33
33
|
const res = await axios_1.default.request(config);
|
|
34
34
|
if (res.status === 204 || res.status === 200) {
|
|
35
35
|
if (res.data?.taken === true) {
|
|
36
|
-
return { status: 'taken', message: '
|
|
36
|
+
return { status: 'taken', message: 'Username already taken' };
|
|
37
37
|
}
|
|
38
38
|
return { status: 'available' };
|
|
39
39
|
}
|
|
@@ -43,29 +43,28 @@ async function checkUsername(username, token, pool) {
|
|
|
43
43
|
}
|
|
44
44
|
if (res.status === 400) {
|
|
45
45
|
if (res.data?.taken === true) {
|
|
46
|
-
return { status: 'taken', message: '
|
|
46
|
+
return { status: 'taken', message: 'Username already taken' };
|
|
47
47
|
}
|
|
48
48
|
const usernameErrors = res.data?.errors?.username?._errors || [];
|
|
49
49
|
const codes = usernameErrors.map((e) => e.code).filter(Boolean);
|
|
50
50
|
if (codes.includes('USERNAME_TOO_MANY_RESULTS')) {
|
|
51
|
-
return { status: 'taken', message: '
|
|
51
|
+
return { status: 'taken', message: 'Username already taken' };
|
|
52
52
|
}
|
|
53
53
|
if (codes.length > 0) {
|
|
54
54
|
return { status: 'invalid', message: codes.join(', ') };
|
|
55
55
|
}
|
|
56
|
-
return { status: 'invalid', message: '
|
|
56
|
+
return { status: 'invalid', message: 'Invalid format' };
|
|
57
57
|
}
|
|
58
58
|
if (res.status === 401 || res.status === 403) {
|
|
59
|
-
return { status: 'error', message: `
|
|
59
|
+
return { status: 'error', message: `Invalid token (${res.status})` };
|
|
60
60
|
}
|
|
61
61
|
return { status: 'error', message: `HTTP ${res.status}` };
|
|
62
62
|
}
|
|
63
63
|
catch (err) {
|
|
64
|
-
return { status: 'error', message: err?.code || err?.message || '
|
|
64
|
+
return { status: 'error', message: err?.code || err?.message || 'Network error' };
|
|
65
65
|
}
|
|
66
66
|
}
|
|
67
67
|
async function validateToken(token, pool) {
|
|
68
|
-
// A lightweight check: a known-taken username should return 400 (taken) rather than 401.
|
|
69
68
|
const res = await checkUsername('discord', token, pool);
|
|
70
|
-
return res.status !== 'error' || !res.message?.includes('
|
|
69
|
+
return res.status !== 'error' || !res.message?.includes('Invalid token');
|
|
71
70
|
}
|
package/dist/index.js
CHANGED
|
@@ -9,35 +9,57 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
9
9
|
const banner_1 = require("./banner");
|
|
10
10
|
const prompts_1 = require("./prompts");
|
|
11
11
|
const config_1 = require("./config");
|
|
12
|
+
const mouse_1 = require("./mouse");
|
|
13
|
+
const updater_1 = require("./updater");
|
|
14
|
+
const version_1 = require("./version");
|
|
12
15
|
const program = new commander_1.Command();
|
|
13
16
|
function guardInteractive() {
|
|
14
17
|
if (!process.stdin.isTTY) {
|
|
15
|
-
console.error(chalk_1.default.yellow('\nwsniper
|
|
16
|
-
'
|
|
18
|
+
console.error(chalk_1.default.yellow('\nwsniper is an interactive tool: please run it in a real terminal.\n' +
|
|
19
|
+
'Example: ') +
|
|
17
20
|
chalk_1.default.cyan('wsniper') +
|
|
18
|
-
chalk_1.default.gray('
|
|
21
|
+
chalk_1.default.gray(' or ') +
|
|
19
22
|
chalk_1.default.cyan('wsniper config'));
|
|
20
23
|
return false;
|
|
21
24
|
}
|
|
22
25
|
return true;
|
|
23
26
|
}
|
|
27
|
+
let sessionHooks = false;
|
|
28
|
+
function startInteractiveSession() {
|
|
29
|
+
if (sessionHooks)
|
|
30
|
+
return;
|
|
31
|
+
sessionHooks = true;
|
|
32
|
+
(0, mouse_1.enableMouse)();
|
|
33
|
+
process.on('exit', mouse_1.disableMouse);
|
|
34
|
+
process.on('SIGINT', () => {
|
|
35
|
+
(0, mouse_1.disableMouse)();
|
|
36
|
+
console.log(chalk_1.default.gray('\nInterrupted.'));
|
|
37
|
+
process.exit(0);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
function clearScreen() {
|
|
41
|
+
process.stdout.write('\x1b[2J\x1b[3J\x1b[H');
|
|
42
|
+
}
|
|
24
43
|
program
|
|
25
44
|
.name('wsniper')
|
|
26
|
-
.description('
|
|
27
|
-
.version(
|
|
45
|
+
.description('Discord username availability checker with rotating proxies')
|
|
46
|
+
.version(version_1.VERSION);
|
|
28
47
|
program
|
|
29
48
|
.command('config')
|
|
30
|
-
.description('
|
|
49
|
+
.description('Configure the Discord token and proxies')
|
|
31
50
|
.action(async () => {
|
|
32
51
|
if (!guardInteractive())
|
|
33
52
|
return;
|
|
53
|
+
clearScreen();
|
|
34
54
|
(0, banner_1.printBanner)();
|
|
55
|
+
await (0, updater_1.checkForUpdates)();
|
|
56
|
+
startInteractiveSession();
|
|
35
57
|
const config = (0, config_1.loadConfig)();
|
|
36
58
|
await (0, prompts_1.configureSettings)(config, (c) => (0, config_1.saveConfig)(c));
|
|
37
59
|
});
|
|
38
60
|
program
|
|
39
61
|
.command('path')
|
|
40
|
-
.description('
|
|
62
|
+
.description('Show the config file path')
|
|
41
63
|
.action(() => {
|
|
42
64
|
console.log(config_1.CONFIG_PATH);
|
|
43
65
|
});
|
|
@@ -45,15 +67,20 @@ program
|
|
|
45
67
|
.action(async () => {
|
|
46
68
|
if (!guardInteractive())
|
|
47
69
|
return;
|
|
70
|
+
clearScreen();
|
|
48
71
|
(0, banner_1.printBanner)();
|
|
72
|
+
await (0, updater_1.checkForUpdates)();
|
|
73
|
+
startInteractiveSession();
|
|
49
74
|
const config = (0, config_1.loadConfig)();
|
|
50
75
|
await (0, prompts_1.mainMenu)(config, (c) => (0, config_1.saveConfig)(c));
|
|
51
76
|
});
|
|
52
77
|
program.parseAsync(process.argv).catch((err) => {
|
|
53
78
|
if (err?.name === 'ExitPromptError') {
|
|
54
|
-
|
|
79
|
+
(0, mouse_1.disableMouse)();
|
|
80
|
+
console.log(chalk_1.default.gray('\nInterrupted.'));
|
|
55
81
|
return;
|
|
56
82
|
}
|
|
57
|
-
|
|
83
|
+
(0, mouse_1.disableMouse)();
|
|
84
|
+
console.error(chalk_1.default.red('\nAn error occurred:'), err?.message || err);
|
|
58
85
|
process.exit(1);
|
|
59
86
|
});
|
package/dist/mouse.js
ADDED
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.enableMouse = enableMouse;
|
|
4
|
+
exports.disableMouse = disableMouse;
|
|
5
|
+
let enabled = false;
|
|
6
|
+
let patched = false;
|
|
7
|
+
let leftover = '';
|
|
8
|
+
const ARROW_UP = '\x1b[A';
|
|
9
|
+
const ARROW_DOWN = '\x1b[B';
|
|
10
|
+
const MOUSE_SEQ = /\x1b\[<(\d+);(\d+);(\d+)[Mm]/g;
|
|
11
|
+
const PARTIAL_TAIL = /\x1b\[[<>]?\d*(;\d*){0,2}$/;
|
|
12
|
+
function translate(buf) {
|
|
13
|
+
let s = leftover + buf.toString('latin1');
|
|
14
|
+
leftover = '';
|
|
15
|
+
let out = '';
|
|
16
|
+
let last = 0;
|
|
17
|
+
let m;
|
|
18
|
+
MOUSE_SEQ.lastIndex = 0;
|
|
19
|
+
while ((m = MOUSE_SEQ.exec(s)) !== null) {
|
|
20
|
+
out += s.slice(last, m.index);
|
|
21
|
+
const button = parseInt(m[1], 10);
|
|
22
|
+
if (button === 64)
|
|
23
|
+
out += ARROW_UP;
|
|
24
|
+
else if (button === 65)
|
|
25
|
+
out += ARROW_DOWN;
|
|
26
|
+
last = MOUSE_SEQ.lastIndex;
|
|
27
|
+
}
|
|
28
|
+
const remainder = s.slice(last);
|
|
29
|
+
const partial = remainder.match(PARTIAL_TAIL);
|
|
30
|
+
if (partial) {
|
|
31
|
+
leftover = partial[0];
|
|
32
|
+
out += remainder.slice(0, remainder.length - partial[0].length);
|
|
33
|
+
}
|
|
34
|
+
else {
|
|
35
|
+
out += remainder;
|
|
36
|
+
}
|
|
37
|
+
if (out.length === 0)
|
|
38
|
+
return Buffer.alloc(0);
|
|
39
|
+
return Buffer.from(out, 'latin1');
|
|
40
|
+
}
|
|
41
|
+
function enableMouse() {
|
|
42
|
+
if (enabled)
|
|
43
|
+
return;
|
|
44
|
+
process.stdout.write('\x1b[?1000h\x1b[?1006h');
|
|
45
|
+
if (!patched) {
|
|
46
|
+
const stdin = process.stdin;
|
|
47
|
+
const origEmit = stdin.emit.bind(stdin);
|
|
48
|
+
stdin.emit = function (event, ...args) {
|
|
49
|
+
if (event === 'data' && Buffer.isBuffer(args[0])) {
|
|
50
|
+
const translated = translate(args[0]);
|
|
51
|
+
if (translated.length === 0)
|
|
52
|
+
return true;
|
|
53
|
+
args[0] = translated;
|
|
54
|
+
}
|
|
55
|
+
return origEmit(event, ...args);
|
|
56
|
+
};
|
|
57
|
+
patched = true;
|
|
58
|
+
}
|
|
59
|
+
enabled = true;
|
|
60
|
+
}
|
|
61
|
+
function disableMouse() {
|
|
62
|
+
if (!enabled)
|
|
63
|
+
return;
|
|
64
|
+
process.stdout.write('\x1b[?1006l\x1b[?1000l');
|
|
65
|
+
enabled = false;
|
|
66
|
+
}
|
package/dist/prompts.js
CHANGED
|
@@ -16,38 +16,38 @@ const generators_1 = require("./generators");
|
|
|
16
16
|
const checker_1 = require("./checker");
|
|
17
17
|
const ui_1 = require("./ui");
|
|
18
18
|
exports.PATTERN_CHOICES = [
|
|
19
|
-
{ name: '
|
|
20
|
-
{ name: '
|
|
21
|
-
{ name: '
|
|
22
|
-
{ name: '
|
|
23
|
-
{ name: '
|
|
24
|
-
{ name: '
|
|
19
|
+
{ name: 'Letters only (a-z)', value: 'letters' },
|
|
20
|
+
{ name: 'Digits only (0-9)', value: 'digits' },
|
|
21
|
+
{ name: 'Letters + Digits', value: 'letters+digits' },
|
|
22
|
+
{ name: 'Letters + Special characters (._)', value: 'letters+special' },
|
|
23
|
+
{ name: 'Letters + Digits + Special characters', value: 'letters+digits+special' },
|
|
24
|
+
{ name: 'Digits + Special characters', value: 'digits+special' },
|
|
25
25
|
];
|
|
26
26
|
exports.PROXY_FORMAT_LINES = [
|
|
27
|
-
chalk_1.default.gray('
|
|
27
|
+
chalk_1.default.gray('One proxy per line. Use # to comment.'),
|
|
28
28
|
'',
|
|
29
29
|
chalk_1.default.white(' http://ip:port'),
|
|
30
|
-
chalk_1.default.white(' http://
|
|
30
|
+
chalk_1.default.white(' http://user:pass@ip:port'),
|
|
31
31
|
chalk_1.default.white(' https://ip:port'),
|
|
32
32
|
chalk_1.default.white(' socks4://ip:port'),
|
|
33
33
|
chalk_1.default.white(' socks5://ip:port'),
|
|
34
|
-
chalk_1.default.white(' socks5://
|
|
35
|
-
chalk_1.default.gray(' ip:port -> http
|
|
36
|
-
chalk_1.default.gray(' ip:port:
|
|
34
|
+
chalk_1.default.white(' socks5://user:pass@ip:port'),
|
|
35
|
+
chalk_1.default.gray(' ip:port -> http by default'),
|
|
36
|
+
chalk_1.default.gray(' ip:port:user:pass -> http by default'),
|
|
37
37
|
];
|
|
38
38
|
async function mainMenu(config, save) {
|
|
39
39
|
while (true) {
|
|
40
40
|
const { choice } = await inquirer_1.default.prompt({
|
|
41
41
|
type: 'list',
|
|
42
42
|
name: 'choice',
|
|
43
|
-
message: '
|
|
43
|
+
message: 'What do you want to do?',
|
|
44
44
|
choices: [
|
|
45
|
-
{ name: '
|
|
45
|
+
{ name: 'Launch the checker', value: 'check' },
|
|
46
46
|
{
|
|
47
|
-
name: `
|
|
47
|
+
name: `Settings ${config.token ? chalk_1.default.green('(token ok)') : chalk_1.default.red('(no token)')}`,
|
|
48
48
|
value: 'config',
|
|
49
49
|
},
|
|
50
|
-
{ name: '
|
|
50
|
+
{ name: 'Quit', value: 'quit' },
|
|
51
51
|
],
|
|
52
52
|
});
|
|
53
53
|
if (choice === 'check') {
|
|
@@ -57,7 +57,7 @@ async function mainMenu(config, save) {
|
|
|
57
57
|
await configureSettings(config, save);
|
|
58
58
|
}
|
|
59
59
|
else {
|
|
60
|
-
console.log(chalk_1.default.gray('\
|
|
60
|
+
console.log(chalk_1.default.gray('\nGoodbye!'));
|
|
61
61
|
break;
|
|
62
62
|
}
|
|
63
63
|
}
|
|
@@ -67,46 +67,46 @@ async function ensureProxyPool(config) {
|
|
|
67
67
|
if (config.proxy && config.proxy.file && fs_1.default.existsSync(config.proxy.file)) {
|
|
68
68
|
const n = config.proxy.loaded?.length ?? 0;
|
|
69
69
|
choices.push({
|
|
70
|
-
name: `
|
|
70
|
+
name: `Use saved proxies (${n} • ${config.proxy.rotating ? 'rotating' : 'static'})`,
|
|
71
71
|
value: 'saved',
|
|
72
72
|
});
|
|
73
73
|
}
|
|
74
|
-
choices.push({ name: '
|
|
75
|
-
choices.push({ name: '
|
|
74
|
+
choices.push({ name: 'Load a new proxy file', value: 'new' });
|
|
75
|
+
choices.push({ name: 'Direct connection (no proxy)', value: 'direct' });
|
|
76
76
|
const { mode } = await inquirer_1.default.prompt({
|
|
77
77
|
type: 'list',
|
|
78
78
|
name: 'mode',
|
|
79
|
-
message: '
|
|
79
|
+
message: 'Proxy configuration:',
|
|
80
80
|
choices,
|
|
81
81
|
});
|
|
82
82
|
if (mode === 'direct') {
|
|
83
|
-
console.log(chalk_1.default.yellow('
|
|
83
|
+
console.log(chalk_1.default.yellow(' Direct connection selected (not recommended for mass scanning).'));
|
|
84
84
|
return null;
|
|
85
85
|
}
|
|
86
86
|
if (mode === 'saved') {
|
|
87
87
|
return proxies_1.ProxyPool.loadFromFile(config.proxy.file, config.proxy.rotating);
|
|
88
88
|
}
|
|
89
|
-
console.log((0, ui_1.box)('
|
|
89
|
+
console.log((0, ui_1.box)('Proxy format', exports.PROXY_FORMAT_LINES));
|
|
90
90
|
console.log();
|
|
91
91
|
const { file } = await inquirer_1.default.prompt({
|
|
92
92
|
type: 'input',
|
|
93
93
|
name: 'file',
|
|
94
|
-
message: '
|
|
94
|
+
message: 'Path to the proxy .txt file:',
|
|
95
95
|
default: 'proxies.txt',
|
|
96
|
-
validate: (v) => v && fs_1.default.existsSync(v) ? true : '
|
|
96
|
+
validate: (v) => v && fs_1.default.existsSync(v) ? true : 'File not found',
|
|
97
97
|
});
|
|
98
98
|
const { rotating } = await inquirer_1.default.prompt({
|
|
99
99
|
type: 'confirm',
|
|
100
100
|
name: 'rotating',
|
|
101
|
-
message:
|
|
101
|
+
message: 'Are your proxies rotating (the provider changes the IP automatically)?',
|
|
102
102
|
default: true,
|
|
103
103
|
});
|
|
104
104
|
const pool = proxies_1.ProxyPool.loadFromFile(file, rotating);
|
|
105
105
|
if (pool.size === 0) {
|
|
106
|
-
console.log(chalk_1.default.red('
|
|
106
|
+
console.log(chalk_1.default.red(' No valid proxies found in the file.'));
|
|
107
107
|
}
|
|
108
108
|
config.proxy = { file, rotating, loaded: pool.list };
|
|
109
|
-
console.log(chalk_1.default.green(` ${pool.size} proxy(s)
|
|
109
|
+
console.log(chalk_1.default.green(` ${pool.size} proxy(s) loaded.`));
|
|
110
110
|
return pool;
|
|
111
111
|
}
|
|
112
112
|
async function ensureToken(config, save) {
|
|
@@ -114,7 +114,7 @@ async function ensureToken(config, save) {
|
|
|
114
114
|
const { reuse } = await inquirer_1.default.prompt({
|
|
115
115
|
type: 'confirm',
|
|
116
116
|
name: 'reuse',
|
|
117
|
-
message: '
|
|
117
|
+
message: 'Use the saved token?',
|
|
118
118
|
default: true,
|
|
119
119
|
});
|
|
120
120
|
if (reuse)
|
|
@@ -124,8 +124,8 @@ async function ensureToken(config, save) {
|
|
|
124
124
|
type: 'password',
|
|
125
125
|
name: 'token',
|
|
126
126
|
mask: '*',
|
|
127
|
-
message: '
|
|
128
|
-
validate: (v) => (v && v.length > 10 ? true : '
|
|
127
|
+
message: 'Discord token:',
|
|
128
|
+
validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
|
|
129
129
|
});
|
|
130
130
|
config.token = token;
|
|
131
131
|
save(config);
|
|
@@ -135,28 +135,28 @@ async function runChecker(config, save) {
|
|
|
135
135
|
const { pattern } = await inquirer_1.default.prompt({
|
|
136
136
|
type: 'list',
|
|
137
137
|
name: 'pattern',
|
|
138
|
-
message: 'Type
|
|
138
|
+
message: 'Type of username to generate:',
|
|
139
139
|
choices: exports.PATTERN_CHOICES,
|
|
140
140
|
});
|
|
141
141
|
const maxLen = 32;
|
|
142
142
|
const { length } = await inquirer_1.default.prompt({
|
|
143
143
|
type: 'number',
|
|
144
144
|
name: 'length',
|
|
145
|
-
message: `
|
|
145
|
+
message: `Username length (2-${maxLen}):`,
|
|
146
146
|
default: 4,
|
|
147
|
-
validate: (v) => v >= 2 && v <= maxLen ? true : `
|
|
147
|
+
validate: (v) => v >= 2 && v <= maxLen ? true : `Between 2 and ${maxLen}`,
|
|
148
148
|
});
|
|
149
149
|
const maxUnique = (0, generators_1.maxUniqueFor)(pattern, length);
|
|
150
150
|
const { count } = await inquirer_1.default.prompt({
|
|
151
151
|
type: 'number',
|
|
152
152
|
name: 'count',
|
|
153
|
-
message: '
|
|
153
|
+
message: 'How many usernames to check?',
|
|
154
154
|
default: 50,
|
|
155
|
-
validate: (v) => v >= 1 && v <= 100000 ? true : '
|
|
155
|
+
validate: (v) => v >= 1 && v <= 100000 ? true : 'Between 1 and 100000',
|
|
156
156
|
});
|
|
157
157
|
const effectiveCount = Math.min(count, maxUnique);
|
|
158
158
|
if (effectiveCount < count) {
|
|
159
|
-
console.log(chalk_1.default.yellow(`
|
|
159
|
+
console.log(chalk_1.default.yellow(` Only ${maxUnique} possible combinations for "${(0, generators_1.patternLabel)(pattern)}" of length ${length}.`));
|
|
160
160
|
}
|
|
161
161
|
const token = await ensureToken(config, save);
|
|
162
162
|
const pool = await ensureProxyPool(config);
|
|
@@ -164,21 +164,21 @@ async function runChecker(config, save) {
|
|
|
164
164
|
const { concurrency } = await inquirer_1.default.prompt({
|
|
165
165
|
type: 'number',
|
|
166
166
|
name: 'concurrency',
|
|
167
|
-
message: '
|
|
167
|
+
message: 'Concurrency (simultaneous requests):',
|
|
168
168
|
default: pool && pool.size > 0 ? Math.min(pool.size, 10) : 1,
|
|
169
|
-
validate: (v) => (v >= 1 && v <= 100 ? true : '
|
|
169
|
+
validate: (v) => (v >= 1 && v <= 100 ? true : 'Between 1 and 100'),
|
|
170
170
|
});
|
|
171
171
|
const { delay } = await inquirer_1.default.prompt({
|
|
172
172
|
type: 'number',
|
|
173
173
|
name: 'delay',
|
|
174
|
-
message: '
|
|
174
|
+
message: 'Delay between requests (ms):',
|
|
175
175
|
default: 0,
|
|
176
176
|
validate: (v) => v >= 0 ? true : '>= 0',
|
|
177
177
|
});
|
|
178
178
|
const usernames = (0, generators_1.generateUsernames)(pattern, length, effectiveCount);
|
|
179
|
-
console.log(chalk_1.default.cyan(`\
|
|
179
|
+
console.log(chalk_1.default.cyan(`\nGenerating ${usernames.length} usernames (${(0, generators_1.patternLabel)(pattern)}, length ${length})...`));
|
|
180
180
|
const stats = { available: 0, taken: 0, invalid: 0, errors: 0, total: usernames.length };
|
|
181
|
-
const spinner = (0, ora_1.default)({ text: '
|
|
181
|
+
const spinner = (0, ora_1.default)({ text: 'Checking...', spinner: 'dots' }).start();
|
|
182
182
|
const onProgress = (done, total, r) => {
|
|
183
183
|
if (r.status === 'available')
|
|
184
184
|
stats.available++;
|
|
@@ -196,7 +196,7 @@ async function runChecker(config, save) {
|
|
|
196
196
|
`${chalk_1.default.gray('?' + stats.errors)}`;
|
|
197
197
|
if (r.status === 'available') {
|
|
198
198
|
spinner.stop();
|
|
199
|
-
console.log(chalk_1.default.green.bold(' ✓
|
|
199
|
+
console.log(chalk_1.default.green.bold(' ✓ AVAILABLE: ') + chalk_1.default.white.bold(r.username));
|
|
200
200
|
spinner.start();
|
|
201
201
|
}
|
|
202
202
|
};
|
|
@@ -207,9 +207,9 @@ async function runChecker(config, save) {
|
|
|
207
207
|
delayMs: delay,
|
|
208
208
|
onProgress,
|
|
209
209
|
});
|
|
210
|
-
spinner.succeed(chalk_1.default.green('
|
|
210
|
+
spinner.succeed(chalk_1.default.green('Check complete!'));
|
|
211
211
|
console.log();
|
|
212
|
-
console.log((0, ui_1.box)('
|
|
212
|
+
console.log((0, ui_1.box)('Summary', (0, ui_1.summaryLines)(stats)));
|
|
213
213
|
console.log();
|
|
214
214
|
const available = results.filter((r) => r.status === 'available');
|
|
215
215
|
if (available.length > 0) {
|
|
@@ -217,27 +217,27 @@ async function runChecker(config, save) {
|
|
|
217
217
|
const stamp = Date.now();
|
|
218
218
|
const availFile = `available_${stamp}.txt`;
|
|
219
219
|
fs_1.default.writeFileSync(availFile, available.map((r) => r.username).join('\n'), 'utf-8');
|
|
220
|
-
console.log(chalk_1.default.green(`\n
|
|
220
|
+
console.log(chalk_1.default.green(`\n Available usernames saved: ${chalk_1.default.bold(availFile)}`));
|
|
221
221
|
}
|
|
222
222
|
else {
|
|
223
|
-
console.log(chalk_1.default.gray('
|
|
223
|
+
console.log(chalk_1.default.gray(' No available usernames found.'));
|
|
224
224
|
}
|
|
225
225
|
const stamp = Date.now();
|
|
226
226
|
const resFile = `results_${stamp}.txt`;
|
|
227
227
|
fs_1.default.writeFileSync(resFile, results.map((r) => `${r.username}\t${r.status}${r.message ? '\t' + r.message : ''}`).join('\n'), 'utf-8');
|
|
228
|
-
console.log(chalk_1.default.gray(`
|
|
228
|
+
console.log(chalk_1.default.gray(` Full results: ${resFile}\n`));
|
|
229
229
|
}
|
|
230
230
|
async function configureSettings(config, save) {
|
|
231
|
-
console.log((0, ui_1.box)('
|
|
232
|
-
`Token : ${config.token ? chalk_1.default.green('
|
|
233
|
-
`Proxies : ${config.proxy ? `${config.proxy.loaded?.length ?? 0} • ${config.proxy.rotating ? '
|
|
234
|
-
`
|
|
231
|
+
console.log((0, ui_1.box)('Current configuration', [
|
|
232
|
+
`Token : ${config.token ? chalk_1.default.green('set') + chalk_1.default.gray(' (' + config.token.slice(0, 6) + '...)') : chalk_1.default.red('not set')}`,
|
|
233
|
+
`Proxies : ${config.proxy ? `${config.proxy.loaded?.length ?? 0} • ${config.proxy.rotating ? 'rotating' : 'static'}` : chalk_1.default.red('not configured')}`,
|
|
234
|
+
`File : ${config.proxy?.file ?? '-'}`,
|
|
235
235
|
]));
|
|
236
236
|
console.log();
|
|
237
237
|
const { setToken } = await inquirer_1.default.prompt({
|
|
238
238
|
type: 'confirm',
|
|
239
239
|
name: 'setToken',
|
|
240
|
-
message: '
|
|
240
|
+
message: 'Set a new Discord token?',
|
|
241
241
|
default: !config.token,
|
|
242
242
|
});
|
|
243
243
|
if (setToken) {
|
|
@@ -245,17 +245,17 @@ async function configureSettings(config, save) {
|
|
|
245
245
|
type: 'password',
|
|
246
246
|
name: 'token',
|
|
247
247
|
mask: '*',
|
|
248
|
-
message: '
|
|
249
|
-
validate: (v) => (v && v.length > 10 ? true : '
|
|
248
|
+
message: 'Discord token:',
|
|
249
|
+
validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
|
|
250
250
|
});
|
|
251
251
|
config.token = token;
|
|
252
252
|
save(config);
|
|
253
|
-
console.log(chalk_1.default.green(' Token
|
|
253
|
+
console.log(chalk_1.default.green(' Token saved.'));
|
|
254
254
|
}
|
|
255
255
|
const pool = await ensureProxyPool(config);
|
|
256
256
|
if (pool) {
|
|
257
257
|
config.proxy = { ...config.proxy, loaded: pool.list };
|
|
258
258
|
}
|
|
259
259
|
save(config);
|
|
260
|
-
console.log(chalk_1.default.green('\nConfiguration
|
|
260
|
+
console.log(chalk_1.default.green('\nConfiguration saved.'));
|
|
261
261
|
}
|
package/dist/ui.js
CHANGED
|
@@ -73,12 +73,12 @@ function statusLabel(status) {
|
|
|
73
73
|
function availableTable(results) {
|
|
74
74
|
const available = results.filter((r) => r.status === 'available');
|
|
75
75
|
if (available.length === 0)
|
|
76
|
-
return chalk_1.default.gray('
|
|
76
|
+
return chalk_1.default.gray('No available usernames found.');
|
|
77
77
|
const table = new cli_table3_1.default({
|
|
78
78
|
head: [
|
|
79
79
|
chalk_1.default.cyan.bold('#'),
|
|
80
|
-
chalk_1.default.cyan.bold('
|
|
81
|
-
chalk_1.default.cyan.bold('
|
|
80
|
+
chalk_1.default.cyan.bold('Username'),
|
|
81
|
+
chalk_1.default.cyan.bold('Status'),
|
|
82
82
|
],
|
|
83
83
|
colWidths: [6, 26, 16],
|
|
84
84
|
style: { head: [], border: ['gray'] },
|
|
@@ -90,10 +90,10 @@ function availableTable(results) {
|
|
|
90
90
|
}
|
|
91
91
|
function summaryLines(stats) {
|
|
92
92
|
return [
|
|
93
|
-
` ${chalk_1.default.green.bold('
|
|
94
|
-
` ${chalk_1.default.red('
|
|
95
|
-
` ${chalk_1.default.yellow('
|
|
96
|
-
` ${chalk_1.default.gray('
|
|
93
|
+
` ${chalk_1.default.green.bold('Available')} : ${stats.available}`,
|
|
94
|
+
` ${chalk_1.default.red('Taken')} : ${stats.taken}`,
|
|
95
|
+
` ${chalk_1.default.yellow('Invalid')} : ${stats.invalid}`,
|
|
96
|
+
` ${chalk_1.default.gray('Errors')} : ${stats.errors}`,
|
|
97
97
|
` ${chalk_1.default.cyan('Total')} : ${stats.total}`,
|
|
98
98
|
];
|
|
99
99
|
}
|
package/dist/updater.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.isNewer = isNewer;
|
|
7
|
+
exports.checkForUpdates = checkForUpdates;
|
|
8
|
+
const axios_1 = __importDefault(require("axios"));
|
|
9
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const child_process_1 = require("child_process");
|
|
11
|
+
const inquirer_1 = __importDefault(require("inquirer"));
|
|
12
|
+
const version_1 = require("./version");
|
|
13
|
+
const REGISTRY_URL = `https://registry.npmjs.org/${version_1.PACKAGE_NAME}/latest`;
|
|
14
|
+
function parseSemver(v) {
|
|
15
|
+
const clean = v.replace(/^v/, '').trim();
|
|
16
|
+
const parts = clean.split('.').map((p) => parseInt(p, 10) || 0);
|
|
17
|
+
return [parts[0] || 0, parts[1] || 0, parts[2] || 0];
|
|
18
|
+
}
|
|
19
|
+
function isNewer(remote, local) {
|
|
20
|
+
const r = parseSemver(remote);
|
|
21
|
+
const l = parseSemver(local);
|
|
22
|
+
for (let i = 0; i < 3; i++) {
|
|
23
|
+
if (r[i] > l[i])
|
|
24
|
+
return true;
|
|
25
|
+
if (r[i] < l[i])
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
async function fetchLatestVersion() {
|
|
31
|
+
try {
|
|
32
|
+
const res = await axios_1.default.get(REGISTRY_URL, {
|
|
33
|
+
timeout: 5000,
|
|
34
|
+
validateStatus: () => true,
|
|
35
|
+
proxy: false,
|
|
36
|
+
});
|
|
37
|
+
if (res.status === 200 && res.data?.version) {
|
|
38
|
+
return res.data.version;
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
// network error or unreachable, skip update check
|
|
43
|
+
}
|
|
44
|
+
return null;
|
|
45
|
+
}
|
|
46
|
+
async function promptUpdate(latest) {
|
|
47
|
+
const { install } = await inquirer_1.default.prompt({
|
|
48
|
+
type: 'confirm',
|
|
49
|
+
name: 'install',
|
|
50
|
+
message: 'A new update was detected. Do you want to install it? (y/n)',
|
|
51
|
+
default: true,
|
|
52
|
+
});
|
|
53
|
+
return install;
|
|
54
|
+
}
|
|
55
|
+
function installUpdate() {
|
|
56
|
+
return new Promise((resolve) => {
|
|
57
|
+
console.log(chalk_1.default.cyan(' Installing update...'));
|
|
58
|
+
const child = (0, child_process_1.spawn)('npm', ['install', '-g', version_1.PACKAGE_NAME], {
|
|
59
|
+
stdio: 'inherit',
|
|
60
|
+
shell: true,
|
|
61
|
+
});
|
|
62
|
+
child.on('close', () => {
|
|
63
|
+
resolve();
|
|
64
|
+
});
|
|
65
|
+
child.on('error', () => {
|
|
66
|
+
console.log(chalk_1.default.red(' Failed to install update automatically.'));
|
|
67
|
+
console.log(chalk_1.default.gray(` Run manually: npm install -g ${version_1.PACKAGE_NAME}`));
|
|
68
|
+
resolve();
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
async function checkForUpdates() {
|
|
73
|
+
const latest = await fetchLatestVersion();
|
|
74
|
+
if (!latest)
|
|
75
|
+
return;
|
|
76
|
+
if (!isNewer(latest, version_1.VERSION))
|
|
77
|
+
return;
|
|
78
|
+
console.log();
|
|
79
|
+
console.log(boxUpdate(`Update available ${chalk_1.default.gray(version_1.VERSION)} -> ${chalk_1.default.green(latest)}`));
|
|
80
|
+
const install = await promptUpdate(latest);
|
|
81
|
+
if (install) {
|
|
82
|
+
await installUpdate();
|
|
83
|
+
console.log(chalk_1.default.green(' Update complete. Please relaunch wsniper.'));
|
|
84
|
+
process.exit(0);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
console.log(chalk_1.default.gray(' Skipping update. Continuing...\n'));
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
function boxUpdate(message) {
|
|
91
|
+
const inner = ` ${message} `;
|
|
92
|
+
const width = inner.length;
|
|
93
|
+
const top = chalk_1.default.gray('┌' + '─'.repeat(width) + '┐');
|
|
94
|
+
const mid = chalk_1.default.gray('│') + inner + chalk_1.default.gray('│');
|
|
95
|
+
const bot = chalk_1.default.gray('└' + '─'.repeat(width) + '┘');
|
|
96
|
+
return [top, mid, bot].join('\n');
|
|
97
|
+
}
|
package/dist/version.js
ADDED
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"name": "wsnipz", "version": "1.
|
|
1
|
+
{"name": "wsnipz", "version": "1.1.0", "description": "A modern Discord username availability checker CLI with rotating proxy support.", "main": "dist/index.js", "bin": {"wsniper": "dist/index.js", "wsnipz": "dist/index.js"}, "files": ["dist"], "scripts": {"build": "tsc", "dev": "ts-node src/index.ts", "start": "node dist/index.js", "prepublishOnly": "npm run build"}, "keywords": ["discord", "username", "checker", "sniper", "cli", "proxy", "availability", "wsnipz"], "author": "", "license": "MIT", "engines": {"node": ">=16"}, "dependencies": {"axios": "^1.7.7", "chalk": "^4.1.2", "cli-table3": "^0.6.5", "commander": "^11.1.0", "figlet": "^1.8.0", "inquirer": "^8.2.6", "ora": "^5.4.1", "proxy-agent": "^5.0.0"}, "devDependencies": {"@types/figlet": "^1.7.0", "@types/inquirer": "^8.2.10", "@types/node": "^20.16.0", "ts-node": "^10.9.2", "typescript": "^5.6.0"}}
|