wsnipz 1.0.0 → 1.2.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 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 VERSION = '1.0.0';
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 rotatifs • mode interactif`));
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: 'Pseudo déjà pris' };
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: 'Pseudo déjà pris' };
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: 'Pseudo déjà pris' };
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: 'Format invalide' };
56
+ return { status: 'invalid', message: 'Invalid format' };
57
57
  }
58
58
  if (res.status === 401 || res.status === 403) {
59
- return { status: 'error', message: `Token invalide (${res.status})` };
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 || 'Erreur réseau' };
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('Token invalide');
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 est un outil interactif : lance-le dans un terminal réel.\n' +
16
- 'Exemple : ') +
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(' ou ') +
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('Vérificateur de disponibilité de pseudos Discord avec proxies rotatifs')
27
- .version('1.0.0');
45
+ .description('Discord username availability checker with rotating proxies')
46
+ .version(version_1.VERSION);
28
47
  program
29
48
  .command('config')
30
- .description('Configurer le token Discord et les proxies')
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('Afficher le chemin du fichier de configuration')
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
- console.log(chalk_1.default.gray('\nInterrompu.'));
79
+ (0, mouse_1.disableMouse)();
80
+ console.log(chalk_1.default.gray('\nInterrupted.'));
55
81
  return;
56
82
  }
57
- console.error(chalk_1.default.red('\nUne erreur est survenue :'), err?.message || err);
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,41 @@ 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: 'Lettres uniquement (a-z)', value: 'letters' },
20
- { name: 'Chiffres uniquement (0-9)', value: 'digits' },
21
- { name: 'Lettres + Chiffres', value: 'letters+digits' },
22
- { name: 'Lettres + Caractères spéciaux (._)', value: 'letters+special' },
23
- { name: 'Lettres + Chiffres + Caractères spéciaux', value: 'letters+digits+special' },
24
- { name: 'Chiffres + Caractères spéciaux', value: 'digits+special' },
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('Un proxy par ligne. # pour commenter.'),
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://utilisateur:mdp@ip:port'),
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://utilisateur:mdp@ip:port'),
35
- chalk_1.default.gray(' ip:port -> http par défaut'),
36
- chalk_1.default.gray(' ip:port:utilisateur:mdp -> http par défaut'),
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
+ if (!config.token && !config.proxy) {
40
+ await onboarding(config, save);
41
+ }
39
42
  while (true) {
40
43
  const { choice } = await inquirer_1.default.prompt({
41
44
  type: 'list',
42
45
  name: 'choice',
43
- message: 'Que veux-tu faire ?',
46
+ message: 'What do you want to do?',
44
47
  choices: [
45
- { name: 'Lancer le checker', value: 'check' },
48
+ { name: 'Launch the checker', value: 'check' },
46
49
  {
47
- name: `Configuration ${config.token ? chalk_1.default.green('(token ok)') : chalk_1.default.red('(aucun token)')}`,
50
+ name: `Settings ${config.token ? chalk_1.default.green('(token ok)') : chalk_1.default.red('(no token)')}`,
48
51
  value: 'config',
49
52
  },
50
- { name: 'Quitter', value: 'quit' },
53
+ { name: 'Quit', value: 'quit' },
51
54
  ],
52
55
  });
53
56
  if (choice === 'check') {
@@ -57,56 +60,118 @@ async function mainMenu(config, save) {
57
60
  await configureSettings(config, save);
58
61
  }
59
62
  else {
60
- console.log(chalk_1.default.gray('\nÀ bientôt !'));
63
+ console.log(chalk_1.default.gray('\nGoodbye!'));
61
64
  break;
62
65
  }
63
66
  }
64
67
  }
68
+ async function onboarding(config, save) {
69
+ console.log((0, ui_1.box)('Welcome to WSniper', [
70
+ chalk_1.default.white('This tool checks Discord username availability'),
71
+ chalk_1.default.white('via the official Discord API.'),
72
+ '',
73
+ chalk_1.default.gray('To run checks you need:'),
74
+ chalk_1.default.gray(' • A Discord token (always required to authenticate)'),
75
+ chalk_1.default.gray(' • Proxies (recommended, to rotate your IP)'),
76
+ ]));
77
+ console.log();
78
+ const { hasProxies } = await inquirer_1.default.prompt({
79
+ type: 'confirm',
80
+ name: 'hasProxies',
81
+ message: 'Do you have proxies to use?',
82
+ default: false,
83
+ });
84
+ if (hasProxies) {
85
+ const pool = await loadProxyFile(config);
86
+ if (pool.size === 0) {
87
+ console.log(chalk_1.default.red(' No valid proxies found in the file.'));
88
+ }
89
+ console.log(chalk_1.default.green(` ${pool.size} proxy(s) loaded.`));
90
+ }
91
+ else {
92
+ console.log((0, ui_1.box)('No proxies', [
93
+ chalk_1.default.yellow('Checks will run on your own IP address.'),
94
+ chalk_1.default.gray('This is RISKY: Discord may rate-limit or ban'),
95
+ chalk_1.default.gray('your account/IP on mass scanning.'),
96
+ '',
97
+ chalk_1.default.gray('You can add proxies later in Settings.'),
98
+ ]));
99
+ }
100
+ console.log();
101
+ console.log((0, ui_1.box)('Discord token required', [
102
+ chalk_1.default.white('The availability API requires authentication:'),
103
+ chalk_1.default.gray('your token is sent with each request to authorize'),
104
+ chalk_1.default.gray('the check, even when using proxies.'),
105
+ '',
106
+ chalk_1.default.yellow('Warning: using your account token carries risk.'),
107
+ chalk_1.default.gray('Use an alt account if possible.'),
108
+ ]));
109
+ console.log();
110
+ const { token } = await inquirer_1.default.prompt({
111
+ type: 'password',
112
+ name: 'token',
113
+ mask: '*',
114
+ message: 'Discord token:',
115
+ validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
116
+ });
117
+ config.token = token;
118
+ save(config);
119
+ console.log(chalk_1.default.green('\n Setup complete!'));
120
+ console.log(chalk_1.default.gray(' You can change these anytime in Settings.\n'));
121
+ }
122
+ async function loadProxyFile(config) {
123
+ console.log((0, ui_1.box)('Proxy format', exports.PROXY_FORMAT_LINES));
124
+ console.log();
125
+ const { file } = await inquirer_1.default.prompt({
126
+ type: 'input',
127
+ name: 'file',
128
+ message: 'Path to the proxy .txt file:',
129
+ default: 'proxies.txt',
130
+ validate: (v) => v && fs_1.default.existsSync(v) ? true : 'File not found',
131
+ });
132
+ const { rotating } = await inquirer_1.default.prompt({
133
+ type: 'confirm',
134
+ name: 'rotating',
135
+ message: 'Are your proxies rotating (the provider changes the IP automatically)?',
136
+ default: true,
137
+ });
138
+ const pool = proxies_1.ProxyPool.loadFromFile(file, rotating);
139
+ config.proxy = { file, rotating, loaded: pool.list };
140
+ return pool;
141
+ }
65
142
  async function ensureProxyPool(config) {
66
143
  const choices = [];
67
144
  if (config.proxy && config.proxy.file && fs_1.default.existsSync(config.proxy.file)) {
68
145
  const n = config.proxy.loaded?.length ?? 0;
69
146
  choices.push({
70
- name: `Utiliser les proxies enregistrés (${n} • ${config.proxy.rotating ? 'rotatifs' : 'statiques'})`,
147
+ name: `Use saved proxies (${n} • ${config.proxy.rotating ? 'rotating' : 'static'})`,
71
148
  value: 'saved',
72
149
  });
73
150
  }
74
- choices.push({ name: 'Charger un nouveau fichier de proxies', value: 'new' });
75
- choices.push({ name: 'Connexion directe (sans proxy)', value: 'direct' });
151
+ choices.push({ name: 'Load a new proxy file', value: 'new' });
152
+ choices.push({ name: 'Direct connection (no proxy)', value: 'direct' });
76
153
  const { mode } = await inquirer_1.default.prompt({
77
154
  type: 'list',
78
155
  name: 'mode',
79
- message: 'Configuration des proxies :',
156
+ message: 'Proxy configuration:',
80
157
  choices,
81
158
  });
82
159
  if (mode === 'direct') {
83
- console.log(chalk_1.default.yellow(' Connexion directe sélectionnée (non recommandé pour un scan massif).'));
160
+ console.log((0, ui_1.box)('No proxies', [
161
+ chalk_1.default.yellow('Checks will run on your own IP address.'),
162
+ chalk_1.default.gray('RISKY: Discord may rate-limit or ban your'),
163
+ chalk_1.default.gray('account/IP on mass scanning.'),
164
+ ]));
84
165
  return null;
85
166
  }
86
167
  if (mode === 'saved') {
87
168
  return proxies_1.ProxyPool.loadFromFile(config.proxy.file, config.proxy.rotating);
88
169
  }
89
- console.log((0, ui_1.box)('Format des proxies', exports.PROXY_FORMAT_LINES));
90
- console.log();
91
- const { file } = await inquirer_1.default.prompt({
92
- type: 'input',
93
- name: 'file',
94
- message: 'Chemin du fichier .txt de proxies :',
95
- default: 'proxies.txt',
96
- validate: (v) => v && fs_1.default.existsSync(v) ? true : 'Fichier introuvable',
97
- });
98
- const { rotating } = await inquirer_1.default.prompt({
99
- type: 'confirm',
100
- name: 'rotating',
101
- message: "Vos proxies sont-ils rotatifs (le fournisseur change l'IP automatiquement) ?",
102
- default: true,
103
- });
104
- const pool = proxies_1.ProxyPool.loadFromFile(file, rotating);
170
+ const pool = await loadProxyFile(config);
105
171
  if (pool.size === 0) {
106
- console.log(chalk_1.default.red(' Aucun proxy valide trouvé dans le fichier.'));
172
+ console.log(chalk_1.default.red(' No valid proxies found in the file.'));
107
173
  }
108
- config.proxy = { file, rotating, loaded: pool.list };
109
- console.log(chalk_1.default.green(` ${pool.size} proxy(s) chargé(s).`));
174
+ console.log(chalk_1.default.green(` ${pool.size} proxy(s) loaded.`));
110
175
  return pool;
111
176
  }
112
177
  async function ensureToken(config, save) {
@@ -114,7 +179,7 @@ async function ensureToken(config, save) {
114
179
  const { reuse } = await inquirer_1.default.prompt({
115
180
  type: 'confirm',
116
181
  name: 'reuse',
117
- message: 'Utiliser le token enregistré ?',
182
+ message: 'Use the saved token?',
118
183
  default: true,
119
184
  });
120
185
  if (reuse)
@@ -124,8 +189,8 @@ async function ensureToken(config, save) {
124
189
  type: 'password',
125
190
  name: 'token',
126
191
  mask: '*',
127
- message: 'Token Discord :',
128
- validate: (v) => (v && v.length > 10 ? true : 'Token invalide'),
192
+ message: 'Discord token:',
193
+ validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
129
194
  });
130
195
  config.token = token;
131
196
  save(config);
@@ -135,28 +200,28 @@ async function runChecker(config, save) {
135
200
  const { pattern } = await inquirer_1.default.prompt({
136
201
  type: 'list',
137
202
  name: 'pattern',
138
- message: 'Type de pseudo à générer :',
203
+ message: 'Type of username to generate:',
139
204
  choices: exports.PATTERN_CHOICES,
140
205
  });
141
206
  const maxLen = 32;
142
207
  const { length } = await inquirer_1.default.prompt({
143
208
  type: 'number',
144
209
  name: 'length',
145
- message: `Longueur des pseudos (2-${maxLen}) :`,
210
+ message: `Username length (2-${maxLen}):`,
146
211
  default: 4,
147
- validate: (v) => v >= 2 && v <= maxLen ? true : `Entre 2 et ${maxLen}`,
212
+ validate: (v) => v >= 2 && v <= maxLen ? true : `Between 2 and ${maxLen}`,
148
213
  });
149
214
  const maxUnique = (0, generators_1.maxUniqueFor)(pattern, length);
150
215
  const { count } = await inquirer_1.default.prompt({
151
216
  type: 'number',
152
217
  name: 'count',
153
- message: 'Combien de pseudos vérifier ?',
218
+ message: 'How many usernames to check?',
154
219
  default: 50,
155
- validate: (v) => v >= 1 && v <= 100000 ? true : 'Entre 1 et 100000',
220
+ validate: (v) => v >= 1 && v <= 100000 ? true : 'Between 1 and 100000',
156
221
  });
157
222
  const effectiveCount = Math.min(count, maxUnique);
158
223
  if (effectiveCount < count) {
159
- console.log(chalk_1.default.yellow(` Seulement ${maxUnique} combinaisons possibles pour "${(0, generators_1.patternLabel)(pattern)}" de longueur ${length}.`));
224
+ console.log(chalk_1.default.yellow(` Only ${maxUnique} possible combinations for "${(0, generators_1.patternLabel)(pattern)}" of length ${length}.`));
160
225
  }
161
226
  const token = await ensureToken(config, save);
162
227
  const pool = await ensureProxyPool(config);
@@ -164,21 +229,21 @@ async function runChecker(config, save) {
164
229
  const { concurrency } = await inquirer_1.default.prompt({
165
230
  type: 'number',
166
231
  name: 'concurrency',
167
- message: 'Concurrence (requêtes simultanées) :',
232
+ message: 'Concurrency (simultaneous requests):',
168
233
  default: pool && pool.size > 0 ? Math.min(pool.size, 10) : 1,
169
- validate: (v) => (v >= 1 && v <= 100 ? true : 'Entre 1 et 100'),
234
+ validate: (v) => (v >= 1 && v <= 100 ? true : 'Between 1 and 100'),
170
235
  });
171
236
  const { delay } = await inquirer_1.default.prompt({
172
237
  type: 'number',
173
238
  name: 'delay',
174
- message: 'Délai entre requêtes (ms) :',
239
+ message: 'Delay between requests (ms):',
175
240
  default: 0,
176
241
  validate: (v) => v >= 0 ? true : '>= 0',
177
242
  });
178
243
  const usernames = (0, generators_1.generateUsernames)(pattern, length, effectiveCount);
179
- console.log(chalk_1.default.cyan(`\nGénération de ${usernames.length} pseudos (${(0, generators_1.patternLabel)(pattern)}, longueur ${length})...`));
244
+ console.log(chalk_1.default.cyan(`\nGenerating ${usernames.length} usernames (${(0, generators_1.patternLabel)(pattern)}, length ${length})...`));
180
245
  const stats = { available: 0, taken: 0, invalid: 0, errors: 0, total: usernames.length };
181
- const spinner = (0, ora_1.default)({ text: 'Vérification en cours...', spinner: 'dots' }).start();
246
+ const spinner = (0, ora_1.default)({ text: 'Checking...', spinner: 'dots' }).start();
182
247
  const onProgress = (done, total, r) => {
183
248
  if (r.status === 'available')
184
249
  stats.available++;
@@ -196,7 +261,7 @@ async function runChecker(config, save) {
196
261
  `${chalk_1.default.gray('?' + stats.errors)}`;
197
262
  if (r.status === 'available') {
198
263
  spinner.stop();
199
- console.log(chalk_1.default.green.bold(' ✓ DISPONIBLE : ') + chalk_1.default.white.bold(r.username));
264
+ console.log(chalk_1.default.green.bold(' ✓ AVAILABLE: ') + chalk_1.default.white.bold(r.username));
200
265
  spinner.start();
201
266
  }
202
267
  };
@@ -207,9 +272,9 @@ async function runChecker(config, save) {
207
272
  delayMs: delay,
208
273
  onProgress,
209
274
  });
210
- spinner.succeed(chalk_1.default.green('Vérification terminée !'));
275
+ spinner.succeed(chalk_1.default.green('Check complete!'));
211
276
  console.log();
212
- console.log((0, ui_1.box)('Résumé', (0, ui_1.summaryLines)(stats)));
277
+ console.log((0, ui_1.box)('Summary', (0, ui_1.summaryLines)(stats)));
213
278
  console.log();
214
279
  const available = results.filter((r) => r.status === 'available');
215
280
  if (available.length > 0) {
@@ -217,27 +282,27 @@ async function runChecker(config, save) {
217
282
  const stamp = Date.now();
218
283
  const availFile = `available_${stamp}.txt`;
219
284
  fs_1.default.writeFileSync(availFile, available.map((r) => r.username).join('\n'), 'utf-8');
220
- console.log(chalk_1.default.green(`\n Pseudos disponibles sauvegardés : ${chalk_1.default.bold(availFile)}`));
285
+ console.log(chalk_1.default.green(`\n Available usernames saved: ${chalk_1.default.bold(availFile)}`));
221
286
  }
222
287
  else {
223
- console.log(chalk_1.default.gray(' Aucun pseudo disponible trouvé.'));
288
+ console.log(chalk_1.default.gray(' No available usernames found.'));
224
289
  }
225
290
  const stamp = Date.now();
226
291
  const resFile = `results_${stamp}.txt`;
227
292
  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(` Résultats complets : ${resFile}\n`));
293
+ console.log(chalk_1.default.gray(` Full results: ${resFile}\n`));
229
294
  }
230
295
  async function configureSettings(config, save) {
231
- console.log((0, ui_1.box)('Configuration actuelle', [
232
- `Token : ${config.token ? chalk_1.default.green('défini') + chalk_1.default.gray(' (' + config.token.slice(0, 6) + '...)') : chalk_1.default.red('non défini')}`,
233
- `Proxies : ${config.proxy ? `${config.proxy.loaded?.length ?? 0} • ${config.proxy.rotating ? 'rotatifs' : 'statiques'}` : chalk_1.default.red('non configurés')}`,
234
- `Fichier : ${config.proxy?.file ?? '-'}`,
296
+ console.log((0, ui_1.box)('Current configuration', [
297
+ `Token : ${config.token ? chalk_1.default.green('set') + chalk_1.default.gray(' (' + config.token.slice(0, 6) + '...)') : chalk_1.default.red('not set')}`,
298
+ `Proxies : ${config.proxy ? `${config.proxy.loaded?.length ?? 0} • ${config.proxy.rotating ? 'rotating' : 'static'}` : chalk_1.default.red('not configured')}`,
299
+ `File : ${config.proxy?.file ?? '-'}`,
235
300
  ]));
236
301
  console.log();
237
302
  const { setToken } = await inquirer_1.default.prompt({
238
303
  type: 'confirm',
239
304
  name: 'setToken',
240
- message: 'Définir un nouveau token Discord ?',
305
+ message: 'Set a new Discord token?',
241
306
  default: !config.token,
242
307
  });
243
308
  if (setToken) {
@@ -245,17 +310,17 @@ async function configureSettings(config, save) {
245
310
  type: 'password',
246
311
  name: 'token',
247
312
  mask: '*',
248
- message: 'Token Discord :',
249
- validate: (v) => (v && v.length > 10 ? true : 'Token invalide'),
313
+ message: 'Discord token:',
314
+ validate: (v) => (v && v.length > 10 ? true : 'Invalid token'),
250
315
  });
251
316
  config.token = token;
252
317
  save(config);
253
- console.log(chalk_1.default.green(' Token enregistré.'));
318
+ console.log(chalk_1.default.green(' Token saved.'));
254
319
  }
255
320
  const pool = await ensureProxyPool(config);
256
321
  if (pool) {
257
322
  config.proxy = { ...config.proxy, loaded: pool.list };
258
323
  }
259
324
  save(config);
260
- console.log(chalk_1.default.green('\nConfiguration enregistrée.'));
325
+ console.log(chalk_1.default.green('\nConfiguration saved.'));
261
326
  }
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('Aucun pseudo disponible trouvé.');
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('Pseudo'),
81
- chalk_1.default.cyan.bold('Statut'),
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('Disponibles')} : ${stats.available}`,
94
- ` ${chalk_1.default.red('Pris')} : ${stats.taken}`,
95
- ` ${chalk_1.default.yellow('Invalides')} : ${stats.invalid}`,
96
- ` ${chalk_1.default.gray('Erreurs')} : ${stats.errors}`,
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
  }
@@ -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
+ }
@@ -0,0 +1,5 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.VERSION = exports.PACKAGE_NAME = void 0;
4
+ exports.PACKAGE_NAME = 'wsnipz';
5
+ exports.VERSION = '1.2.0';
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name": "wsnipz", "version": "1.0.0", "description": "A modern Discord username availability checker CLI with rotating proxy support.", "main": "dist/index.js", "bin": {"wsniper": "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"}}
1
+ {"name": "wsnipz", "version": "1.2.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"}}