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 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,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: '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
39
  while (true) {
40
40
  const { choice } = await inquirer_1.default.prompt({
41
41
  type: 'list',
42
42
  name: 'choice',
43
- message: 'Que veux-tu faire ?',
43
+ message: 'What do you want to do?',
44
44
  choices: [
45
- { name: 'Lancer le checker', value: 'check' },
45
+ { name: 'Launch the checker', value: 'check' },
46
46
  {
47
- name: `Configuration ${config.token ? chalk_1.default.green('(token ok)') : chalk_1.default.red('(aucun token)')}`,
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: 'Quitter', value: 'quit' },
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('\nÀ bientôt !'));
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: `Utiliser les proxies enregistrés (${n} • ${config.proxy.rotating ? 'rotatifs' : 'statiques'})`,
70
+ name: `Use saved proxies (${n} • ${config.proxy.rotating ? 'rotating' : 'static'})`,
71
71
  value: 'saved',
72
72
  });
73
73
  }
74
- choices.push({ name: 'Charger un nouveau fichier de proxies', value: 'new' });
75
- choices.push({ name: 'Connexion directe (sans proxy)', value: 'direct' });
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: 'Configuration des proxies :',
79
+ message: 'Proxy configuration:',
80
80
  choices,
81
81
  });
82
82
  if (mode === 'direct') {
83
- console.log(chalk_1.default.yellow(' Connexion directe sélectionnée (non recommandé pour un scan massif).'));
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)('Format des proxies', exports.PROXY_FORMAT_LINES));
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: 'Chemin du fichier .txt de proxies :',
94
+ message: 'Path to the proxy .txt file:',
95
95
  default: 'proxies.txt',
96
- validate: (v) => v && fs_1.default.existsSync(v) ? true : 'Fichier introuvable',
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: "Vos proxies sont-ils rotatifs (le fournisseur change l'IP automatiquement) ?",
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(' Aucun proxy valide trouvé dans le fichier.'));
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) chargé(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: 'Utiliser le token enregistré ?',
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: 'Token Discord :',
128
- validate: (v) => (v && v.length > 10 ? true : 'Token invalide'),
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 de pseudo à générer :',
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: `Longueur des pseudos (2-${maxLen}) :`,
145
+ message: `Username length (2-${maxLen}):`,
146
146
  default: 4,
147
- validate: (v) => v >= 2 && v <= maxLen ? true : `Entre 2 et ${maxLen}`,
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: 'Combien de pseudos vérifier ?',
153
+ message: 'How many usernames to check?',
154
154
  default: 50,
155
- validate: (v) => v >= 1 && v <= 100000 ? true : 'Entre 1 et 100000',
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(` Seulement ${maxUnique} combinaisons possibles pour "${(0, generators_1.patternLabel)(pattern)}" de longueur ${length}.`));
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: 'Concurrence (requêtes simultanées) :',
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 : 'Entre 1 et 100'),
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: 'Délai entre requêtes (ms) :',
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(`\nGénération de ${usernames.length} pseudos (${(0, generators_1.patternLabel)(pattern)}, longueur ${length})...`));
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: 'Vérification en cours...', spinner: 'dots' }).start();
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(' ✓ DISPONIBLE : ') + chalk_1.default.white.bold(r.username));
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('Vérification terminée !'));
210
+ spinner.succeed(chalk_1.default.green('Check complete!'));
211
211
  console.log();
212
- console.log((0, ui_1.box)('Résumé', (0, ui_1.summaryLines)(stats)));
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 Pseudos disponibles sauvegardés : ${chalk_1.default.bold(availFile)}`));
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(' Aucun pseudo disponible trouvé.'));
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(` Résultats complets : ${resFile}\n`));
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)('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 ?? '-'}`,
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: 'Définir un nouveau token Discord ?',
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: 'Token Discord :',
249
- validate: (v) => (v && v.length > 10 ? true : 'Token invalide'),
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 enregistré.'));
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 enregistrée.'));
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('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.1.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.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"}}