wsnipz 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/banner.js ADDED
@@ -0,0 +1,25 @@
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.printBanner = printBanner;
7
+ const figlet_1 = __importDefault(require("figlet"));
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const ui_1 = require("./ui");
10
+ const VERSION = '1.0.0';
11
+ function printBanner() {
12
+ const art = figlet_1.default.textSync('WSniper', {
13
+ font: 'Standard',
14
+ horizontalLayout: 'fitted',
15
+ verticalLayout: 'default',
16
+ });
17
+ const colored = (0, ui_1.gradient)(['#5865F2', '#9B59B6', '#EB459E'], art);
18
+ console.log(colored);
19
+ const tag = ' Discord Username Availability Checker ';
20
+ const line = chalk_1.default.gray('─'.repeat(tag.length));
21
+ console.log(chalk_1.default.gray(tag));
22
+ console.log(line);
23
+ console.log(chalk_1.default.gray(` v${VERSION} • proxies rotatifs • mode interactif`));
24
+ console.log();
25
+ }
@@ -0,0 +1,40 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.checkUsernames = checkUsernames;
4
+ const discord_1 = require("./discord");
5
+ function sleep(ms) {
6
+ return new Promise((r) => setTimeout(r, ms));
7
+ }
8
+ async function checkUsernames(usernames, opts) {
9
+ const results = [];
10
+ let cursor = 0;
11
+ let done = 0;
12
+ const total = usernames.length;
13
+ async function worker() {
14
+ while (true) {
15
+ const i = cursor++;
16
+ if (i >= total)
17
+ break;
18
+ const username = usernames[i];
19
+ let res = await (0, discord_1.checkUsername)(username, opts.token, opts.pool);
20
+ if (res.status === 'ratelimited') {
21
+ const waitMs = Math.max((res.retryAfter ?? 1) * 1000, 500);
22
+ await sleep(waitMs);
23
+ res = await (0, discord_1.checkUsername)(username, opts.token, opts.pool);
24
+ }
25
+ const result = {
26
+ username,
27
+ status: res.status,
28
+ message: res.message,
29
+ };
30
+ results.push(result);
31
+ done++;
32
+ opts.onProgress?.(done, total, result);
33
+ if (opts.delayMs > 0)
34
+ await sleep(opts.delayMs);
35
+ }
36
+ }
37
+ const workers = Array.from({ length: Math.max(opts.concurrency, 1) }, () => worker());
38
+ await Promise.all(workers);
39
+ return results;
40
+ }
package/dist/config.js ADDED
@@ -0,0 +1,41 @@
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.CONFIG_PATH = void 0;
7
+ exports.loadConfig = loadConfig;
8
+ exports.saveConfig = saveConfig;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const os_1 = __importDefault(require("os"));
12
+ const CONFIG_DIR = path_1.default.join(os_1.default.homedir(), '.wsniper');
13
+ const CONFIG_FILE = path_1.default.join(CONFIG_DIR, 'config.json');
14
+ exports.CONFIG_PATH = CONFIG_FILE;
15
+ function loadConfig() {
16
+ try {
17
+ if (fs_1.default.existsSync(CONFIG_FILE)) {
18
+ const raw = fs_1.default.readFileSync(CONFIG_FILE, 'utf-8');
19
+ const parsed = JSON.parse(raw);
20
+ return {
21
+ token: parsed.token ?? null,
22
+ proxy: parsed.proxy ?? null,
23
+ };
24
+ }
25
+ }
26
+ catch {
27
+ // ignore malformed config
28
+ }
29
+ return { token: null, proxy: null };
30
+ }
31
+ function saveConfig(config) {
32
+ try {
33
+ if (!fs_1.default.existsSync(CONFIG_DIR)) {
34
+ fs_1.default.mkdirSync(CONFIG_DIR, { recursive: true });
35
+ }
36
+ fs_1.default.writeFileSync(CONFIG_FILE, JSON.stringify(config, null, 2), 'utf-8');
37
+ }
38
+ catch {
39
+ // ignore write errors
40
+ }
41
+ }
@@ -0,0 +1,71 @@
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.checkUsername = checkUsername;
7
+ exports.validateToken = validateToken;
8
+ const axios_1 = __importDefault(require("axios"));
9
+ const POMELO_ENDPOINT = 'https://discord.com/api/v9/users/@me/pomelo-attempt';
10
+ const DEFAULT_HEADERS = {
11
+ 'Content-Type': 'application/json',
12
+ Accept: 'application/json',
13
+ 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36',
14
+ 'x-discord-locale': 'en-US',
15
+ };
16
+ async function checkUsername(username, token, pool) {
17
+ const config = {
18
+ method: 'POST',
19
+ url: POMELO_ENDPOINT,
20
+ headers: { ...DEFAULT_HEADERS, Authorization: token },
21
+ data: { username },
22
+ validateStatus: () => true,
23
+ timeout: 15000,
24
+ proxy: false,
25
+ };
26
+ const proxyUrl = pool?.next() ?? undefined;
27
+ if (proxyUrl) {
28
+ const agent = pool.createAgent(proxyUrl);
29
+ config.httpAgent = agent;
30
+ config.httpsAgent = agent;
31
+ }
32
+ try {
33
+ const res = await axios_1.default.request(config);
34
+ if (res.status === 204 || res.status === 200) {
35
+ if (res.data?.taken === true) {
36
+ return { status: 'taken', message: 'Pseudo déjà pris' };
37
+ }
38
+ return { status: 'available' };
39
+ }
40
+ if (res.status === 429) {
41
+ const retryAfter = Number(res.data?.retry_after ?? 1);
42
+ return { status: 'ratelimited', retryAfter: isNaN(retryAfter) ? 1 : retryAfter };
43
+ }
44
+ if (res.status === 400) {
45
+ if (res.data?.taken === true) {
46
+ return { status: 'taken', message: 'Pseudo déjà pris' };
47
+ }
48
+ const usernameErrors = res.data?.errors?.username?._errors || [];
49
+ const codes = usernameErrors.map((e) => e.code).filter(Boolean);
50
+ if (codes.includes('USERNAME_TOO_MANY_RESULTS')) {
51
+ return { status: 'taken', message: 'Pseudo déjà pris' };
52
+ }
53
+ if (codes.length > 0) {
54
+ return { status: 'invalid', message: codes.join(', ') };
55
+ }
56
+ return { status: 'invalid', message: 'Format invalide' };
57
+ }
58
+ if (res.status === 401 || res.status === 403) {
59
+ return { status: 'error', message: `Token invalide (${res.status})` };
60
+ }
61
+ return { status: 'error', message: `HTTP ${res.status}` };
62
+ }
63
+ catch (err) {
64
+ return { status: 'error', message: err?.code || err?.message || 'Erreur réseau' };
65
+ }
66
+ }
67
+ async function validateToken(token, pool) {
68
+ // A lightweight check: a known-taken username should return 400 (taken) rather than 401.
69
+ const res = await checkUsername('discord', token, pool);
70
+ return res.status !== 'error' || !res.message?.includes('Token invalide');
71
+ }
@@ -0,0 +1,59 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SPECIAL = exports.DIGITS = exports.LETTERS = void 0;
4
+ exports.charsetFor = charsetFor;
5
+ exports.patternLabel = patternLabel;
6
+ exports.generateUsernames = generateUsernames;
7
+ exports.maxUniqueFor = maxUniqueFor;
8
+ exports.LETTERS = 'abcdefghijklmnopqrstuvwxyz';
9
+ exports.DIGITS = '0123456789';
10
+ exports.SPECIAL = '._';
11
+ const PATTERN_SETS = {
12
+ 'letters': exports.LETTERS,
13
+ 'digits': exports.DIGITS,
14
+ 'letters+digits': exports.LETTERS + exports.DIGITS,
15
+ 'letters+special': exports.LETTERS + exports.SPECIAL,
16
+ 'letters+digits+special': exports.LETTERS + exports.DIGITS + exports.SPECIAL,
17
+ 'digits+special': exports.DIGITS + exports.SPECIAL,
18
+ };
19
+ const PATTERN_LABELS = {
20
+ 'letters': 'Lettres (a-z)',
21
+ 'digits': 'Chiffres (0-9)',
22
+ 'letters+digits': 'Lettres + Chiffres',
23
+ 'letters+special': 'Lettres + Caractères spéciaux (._)',
24
+ 'letters+digits+special': 'Lettres + Chiffres + Caractères spéciaux',
25
+ 'digits+special': 'Chiffres + Caractères spéciaux',
26
+ };
27
+ function charsetFor(pattern) {
28
+ return PATTERN_SETS[pattern];
29
+ }
30
+ function patternLabel(pattern) {
31
+ return PATTERN_LABELS[pattern] || pattern;
32
+ }
33
+ function randomString(length, charset) {
34
+ let out = '';
35
+ for (let i = 0; i < length; i++) {
36
+ out += charset[Math.floor(Math.random() * charset.length)];
37
+ }
38
+ return out;
39
+ }
40
+ function generateUsernames(pattern, length, count) {
41
+ const charset = charsetFor(pattern);
42
+ const seen = new Set();
43
+ const out = [];
44
+ const maxAttempts = count * 1000;
45
+ let attempts = 0;
46
+ while (out.length < count && attempts < maxAttempts) {
47
+ attempts++;
48
+ const name = randomString(length, charset);
49
+ if (!seen.has(name)) {
50
+ seen.add(name);
51
+ out.push(name);
52
+ }
53
+ }
54
+ return out;
55
+ }
56
+ function maxUniqueFor(pattern, length) {
57
+ const charset = charsetFor(pattern);
58
+ return Math.pow(charset.length, length);
59
+ }
package/dist/index.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ var __importDefault = (this && this.__importDefault) || function (mod) {
4
+ return (mod && mod.__esModule) ? mod : { "default": mod };
5
+ };
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ const commander_1 = require("commander");
8
+ const chalk_1 = __importDefault(require("chalk"));
9
+ const banner_1 = require("./banner");
10
+ const prompts_1 = require("./prompts");
11
+ const config_1 = require("./config");
12
+ const program = new commander_1.Command();
13
+ function guardInteractive() {
14
+ 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 : ') +
17
+ chalk_1.default.cyan('wsniper') +
18
+ chalk_1.default.gray(' ou ') +
19
+ chalk_1.default.cyan('wsniper config'));
20
+ return false;
21
+ }
22
+ return true;
23
+ }
24
+ program
25
+ .name('wsniper')
26
+ .description('Vérificateur de disponibilité de pseudos Discord avec proxies rotatifs')
27
+ .version('1.0.0');
28
+ program
29
+ .command('config')
30
+ .description('Configurer le token Discord et les proxies')
31
+ .action(async () => {
32
+ if (!guardInteractive())
33
+ return;
34
+ (0, banner_1.printBanner)();
35
+ const config = (0, config_1.loadConfig)();
36
+ await (0, prompts_1.configureSettings)(config, (c) => (0, config_1.saveConfig)(c));
37
+ });
38
+ program
39
+ .command('path')
40
+ .description('Afficher le chemin du fichier de configuration')
41
+ .action(() => {
42
+ console.log(config_1.CONFIG_PATH);
43
+ });
44
+ program
45
+ .action(async () => {
46
+ if (!guardInteractive())
47
+ return;
48
+ (0, banner_1.printBanner)();
49
+ const config = (0, config_1.loadConfig)();
50
+ await (0, prompts_1.mainMenu)(config, (c) => (0, config_1.saveConfig)(c));
51
+ });
52
+ program.parseAsync(process.argv).catch((err) => {
53
+ if (err?.name === 'ExitPromptError') {
54
+ console.log(chalk_1.default.gray('\nInterrompu.'));
55
+ return;
56
+ }
57
+ console.error(chalk_1.default.red('\nUne erreur est survenue :'), err?.message || err);
58
+ process.exit(1);
59
+ });
@@ -0,0 +1,261 @@
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.PROXY_FORMAT_LINES = exports.PATTERN_CHOICES = void 0;
7
+ exports.mainMenu = mainMenu;
8
+ exports.runChecker = runChecker;
9
+ exports.configureSettings = configureSettings;
10
+ const inquirer_1 = __importDefault(require("inquirer"));
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const chalk_1 = __importDefault(require("chalk"));
13
+ const ora_1 = __importDefault(require("ora"));
14
+ const proxies_1 = require("./proxies");
15
+ const generators_1 = require("./generators");
16
+ const checker_1 = require("./checker");
17
+ const ui_1 = require("./ui");
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' },
25
+ ];
26
+ exports.PROXY_FORMAT_LINES = [
27
+ chalk_1.default.gray('Un proxy par ligne. # pour commenter.'),
28
+ '',
29
+ chalk_1.default.white(' http://ip:port'),
30
+ chalk_1.default.white(' http://utilisateur:mdp@ip:port'),
31
+ chalk_1.default.white(' https://ip:port'),
32
+ chalk_1.default.white(' socks4://ip:port'),
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'),
37
+ ];
38
+ async function mainMenu(config, save) {
39
+ while (true) {
40
+ const { choice } = await inquirer_1.default.prompt({
41
+ type: 'list',
42
+ name: 'choice',
43
+ message: 'Que veux-tu faire ?',
44
+ choices: [
45
+ { name: 'Lancer le checker', value: 'check' },
46
+ {
47
+ name: `Configuration ${config.token ? chalk_1.default.green('(token ok)') : chalk_1.default.red('(aucun token)')}`,
48
+ value: 'config',
49
+ },
50
+ { name: 'Quitter', value: 'quit' },
51
+ ],
52
+ });
53
+ if (choice === 'check') {
54
+ await runChecker(config, save);
55
+ }
56
+ else if (choice === 'config') {
57
+ await configureSettings(config, save);
58
+ }
59
+ else {
60
+ console.log(chalk_1.default.gray('\nÀ bientôt !'));
61
+ break;
62
+ }
63
+ }
64
+ }
65
+ async function ensureProxyPool(config) {
66
+ const choices = [];
67
+ if (config.proxy && config.proxy.file && fs_1.default.existsSync(config.proxy.file)) {
68
+ const n = config.proxy.loaded?.length ?? 0;
69
+ choices.push({
70
+ name: `Utiliser les proxies enregistrés (${n} • ${config.proxy.rotating ? 'rotatifs' : 'statiques'})`,
71
+ value: 'saved',
72
+ });
73
+ }
74
+ choices.push({ name: 'Charger un nouveau fichier de proxies', value: 'new' });
75
+ choices.push({ name: 'Connexion directe (sans proxy)', value: 'direct' });
76
+ const { mode } = await inquirer_1.default.prompt({
77
+ type: 'list',
78
+ name: 'mode',
79
+ message: 'Configuration des proxies :',
80
+ choices,
81
+ });
82
+ if (mode === 'direct') {
83
+ console.log(chalk_1.default.yellow(' Connexion directe sélectionnée (non recommandé pour un scan massif).'));
84
+ return null;
85
+ }
86
+ if (mode === 'saved') {
87
+ return proxies_1.ProxyPool.loadFromFile(config.proxy.file, config.proxy.rotating);
88
+ }
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);
105
+ if (pool.size === 0) {
106
+ console.log(chalk_1.default.red(' Aucun proxy valide trouvé dans le fichier.'));
107
+ }
108
+ config.proxy = { file, rotating, loaded: pool.list };
109
+ console.log(chalk_1.default.green(` ${pool.size} proxy(s) chargé(s).`));
110
+ return pool;
111
+ }
112
+ async function ensureToken(config, save) {
113
+ if (config.token) {
114
+ const { reuse } = await inquirer_1.default.prompt({
115
+ type: 'confirm',
116
+ name: 'reuse',
117
+ message: 'Utiliser le token enregistré ?',
118
+ default: true,
119
+ });
120
+ if (reuse)
121
+ return config.token;
122
+ }
123
+ const { token } = await inquirer_1.default.prompt({
124
+ type: 'password',
125
+ name: 'token',
126
+ mask: '*',
127
+ message: 'Token Discord :',
128
+ validate: (v) => (v && v.length > 10 ? true : 'Token invalide'),
129
+ });
130
+ config.token = token;
131
+ save(config);
132
+ return token;
133
+ }
134
+ async function runChecker(config, save) {
135
+ const { pattern } = await inquirer_1.default.prompt({
136
+ type: 'list',
137
+ name: 'pattern',
138
+ message: 'Type de pseudo à générer :',
139
+ choices: exports.PATTERN_CHOICES,
140
+ });
141
+ const maxLen = 32;
142
+ const { length } = await inquirer_1.default.prompt({
143
+ type: 'number',
144
+ name: 'length',
145
+ message: `Longueur des pseudos (2-${maxLen}) :`,
146
+ default: 4,
147
+ validate: (v) => v >= 2 && v <= maxLen ? true : `Entre 2 et ${maxLen}`,
148
+ });
149
+ const maxUnique = (0, generators_1.maxUniqueFor)(pattern, length);
150
+ const { count } = await inquirer_1.default.prompt({
151
+ type: 'number',
152
+ name: 'count',
153
+ message: 'Combien de pseudos vérifier ?',
154
+ default: 50,
155
+ validate: (v) => v >= 1 && v <= 100000 ? true : 'Entre 1 et 100000',
156
+ });
157
+ const effectiveCount = Math.min(count, maxUnique);
158
+ if (effectiveCount < count) {
159
+ console.log(chalk_1.default.yellow(` Seulement ${maxUnique} combinaisons possibles pour "${(0, generators_1.patternLabel)(pattern)}" de longueur ${length}.`));
160
+ }
161
+ const token = await ensureToken(config, save);
162
+ const pool = await ensureProxyPool(config);
163
+ save(config);
164
+ const { concurrency } = await inquirer_1.default.prompt({
165
+ type: 'number',
166
+ name: 'concurrency',
167
+ message: 'Concurrence (requêtes simultanées) :',
168
+ default: pool && pool.size > 0 ? Math.min(pool.size, 10) : 1,
169
+ validate: (v) => (v >= 1 && v <= 100 ? true : 'Entre 1 et 100'),
170
+ });
171
+ const { delay } = await inquirer_1.default.prompt({
172
+ type: 'number',
173
+ name: 'delay',
174
+ message: 'Délai entre requêtes (ms) :',
175
+ default: 0,
176
+ validate: (v) => v >= 0 ? true : '>= 0',
177
+ });
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})...`));
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();
182
+ const onProgress = (done, total, r) => {
183
+ if (r.status === 'available')
184
+ stats.available++;
185
+ else if (r.status === 'taken')
186
+ stats.taken++;
187
+ else if (r.status === 'invalid')
188
+ stats.invalid++;
189
+ else
190
+ stats.errors++;
191
+ spinner.text =
192
+ `[${done}/${total}] ` +
193
+ `${chalk_1.default.green('✓' + stats.available)} ` +
194
+ `${chalk_1.default.red('✗' + stats.taken)} ` +
195
+ `${chalk_1.default.yellow('!' + stats.invalid)} ` +
196
+ `${chalk_1.default.gray('?' + stats.errors)}`;
197
+ if (r.status === 'available') {
198
+ spinner.stop();
199
+ console.log(chalk_1.default.green.bold(' ✓ DISPONIBLE : ') + chalk_1.default.white.bold(r.username));
200
+ spinner.start();
201
+ }
202
+ };
203
+ const results = await (0, checker_1.checkUsernames)(usernames, {
204
+ token,
205
+ pool,
206
+ concurrency,
207
+ delayMs: delay,
208
+ onProgress,
209
+ });
210
+ spinner.succeed(chalk_1.default.green('Vérification terminée !'));
211
+ console.log();
212
+ console.log((0, ui_1.box)('Résumé', (0, ui_1.summaryLines)(stats)));
213
+ console.log();
214
+ const available = results.filter((r) => r.status === 'available');
215
+ if (available.length > 0) {
216
+ console.log((0, ui_1.availableTable)(results));
217
+ const stamp = Date.now();
218
+ const availFile = `available_${stamp}.txt`;
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)}`));
221
+ }
222
+ else {
223
+ console.log(chalk_1.default.gray(' Aucun pseudo disponible trouvé.'));
224
+ }
225
+ const stamp = Date.now();
226
+ const resFile = `results_${stamp}.txt`;
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`));
229
+ }
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 ?? '-'}`,
235
+ ]));
236
+ console.log();
237
+ const { setToken } = await inquirer_1.default.prompt({
238
+ type: 'confirm',
239
+ name: 'setToken',
240
+ message: 'Définir un nouveau token Discord ?',
241
+ default: !config.token,
242
+ });
243
+ if (setToken) {
244
+ const { token } = await inquirer_1.default.prompt({
245
+ type: 'password',
246
+ name: 'token',
247
+ mask: '*',
248
+ message: 'Token Discord :',
249
+ validate: (v) => (v && v.length > 10 ? true : 'Token invalide'),
250
+ });
251
+ config.token = token;
252
+ save(config);
253
+ console.log(chalk_1.default.green(' Token enregistré.'));
254
+ }
255
+ const pool = await ensureProxyPool(config);
256
+ if (pool) {
257
+ config.proxy = { ...config.proxy, loaded: pool.list };
258
+ }
259
+ save(config);
260
+ console.log(chalk_1.default.green('\nConfiguration enregistrée.'));
261
+ }
@@ -0,0 +1,84 @@
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.ProxyPool = void 0;
7
+ exports.normalizeProxyUrl = normalizeProxyUrl;
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const { ProxyAgent } = require('proxy-agent');
10
+ function normalizeProxyUrl(raw) {
11
+ let s = raw.trim();
12
+ if (!s)
13
+ return s;
14
+ const hasScheme = /^[a-z0-9]+:\/\//i.test(s);
15
+ if (hasScheme) {
16
+ const idx = s.indexOf('://');
17
+ const scheme = s.slice(0, idx);
18
+ const rest = s.slice(idx + 3);
19
+ const parts = rest.split(':');
20
+ // ip:port:user:pass without an @ sign -> rewrite to scheme://user:pass@ip:port
21
+ if (parts.length >= 4 && !rest.includes('@')) {
22
+ const ip = parts[0];
23
+ const port = parts[1];
24
+ const cred = parts.slice(2);
25
+ const pass = cred.pop();
26
+ const user = cred.join(':');
27
+ return `${scheme}://${encodeURIComponent(user)}:${encodeURIComponent(pass)}@${ip}:${port}`;
28
+ }
29
+ return s;
30
+ }
31
+ // No scheme present
32
+ if (s.includes('@')) {
33
+ return 'http://' + s;
34
+ }
35
+ const parts = s.split(':');
36
+ if (parts.length === 2) {
37
+ return 'http://' + s;
38
+ }
39
+ if (parts.length === 4) {
40
+ const [ip, port, user, pass] = parts;
41
+ return `http://${encodeURIComponent(user)}:${encodeURIComponent(pass)}@${ip}:${port}`;
42
+ }
43
+ if (parts.length === 3) {
44
+ const [ip, port, user] = parts;
45
+ return `http://${encodeURIComponent(user)}:@${ip}:${port}`;
46
+ }
47
+ return 'http://' + s;
48
+ }
49
+ class ProxyPool {
50
+ constructor(proxies = [], rotating = false) {
51
+ this.proxies = [];
52
+ this.index = 0;
53
+ this.rotating = false;
54
+ this.proxies = proxies;
55
+ this.rotating = rotating;
56
+ }
57
+ get size() {
58
+ return this.proxies.length;
59
+ }
60
+ get list() {
61
+ return [...this.proxies];
62
+ }
63
+ static loadFromFile(path, rotating) {
64
+ const content = fs_1.default.readFileSync(path, 'utf-8');
65
+ const proxies = content
66
+ .split(/\r?\n/)
67
+ .map((l) => l.trim())
68
+ .filter((l) => l.length > 0 && !l.startsWith('#'))
69
+ .map(normalizeProxyUrl)
70
+ .filter((l) => l.length > 0);
71
+ return new ProxyPool(proxies, rotating);
72
+ }
73
+ next() {
74
+ if (this.proxies.length === 0)
75
+ return null;
76
+ const proxy = this.proxies[this.index % this.proxies.length];
77
+ this.index++;
78
+ return proxy;
79
+ }
80
+ createAgent(proxyUrl) {
81
+ return new ProxyAgent(proxyUrl);
82
+ }
83
+ }
84
+ exports.ProxyPool = ProxyPool;
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
package/dist/ui.js ADDED
@@ -0,0 +1,99 @@
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.stripAnsi = stripAnsi;
7
+ exports.gradient = gradient;
8
+ exports.box = box;
9
+ exports.statusLabel = statusLabel;
10
+ exports.availableTable = availableTable;
11
+ exports.summaryLines = summaryLines;
12
+ const chalk_1 = __importDefault(require("chalk"));
13
+ const cli_table3_1 = __importDefault(require("cli-table3"));
14
+ const ANSI_RE = /\u001b\[[0-9;]*m/g;
15
+ function stripAnsi(s) {
16
+ return s.replace(ANSI_RE, '');
17
+ }
18
+ function hexToRgb(hex) {
19
+ const h = hex.replace('#', '');
20
+ return [
21
+ parseInt(h.slice(0, 2), 16),
22
+ parseInt(h.slice(2, 4), 16),
23
+ parseInt(h.slice(4, 6), 16),
24
+ ];
25
+ }
26
+ function lerp(a, b, t) {
27
+ return Math.round(a + (b - a) * t);
28
+ }
29
+ function gradient(colors, text) {
30
+ if (colors.length === 0)
31
+ return text;
32
+ if (colors.length === 1) {
33
+ const [r, g, b] = hexToRgb(colors[0]);
34
+ return chalk_1.default.rgb(r, g, b)(text);
35
+ }
36
+ const chars = Array.from(text);
37
+ const n = chars.length;
38
+ const segs = colors.length - 1;
39
+ return chars
40
+ .map((ch, i) => {
41
+ const t = n === 1 ? 0 : i / (n - 1);
42
+ const seg = Math.min(Math.floor(t * segs), segs - 1);
43
+ const localT = t * segs - seg;
44
+ const c1 = hexToRgb(colors[seg]);
45
+ const c2 = hexToRgb(colors[seg + 1]);
46
+ return chalk_1.default.rgb(lerp(c1[0], c2[0], localT), lerp(c1[1], c2[1], localT), lerp(c1[2], c2[2], localT))(ch);
47
+ })
48
+ .join('');
49
+ }
50
+ function box(title, lines) {
51
+ const all = [chalk_1.default.bold.cyan(title), ...lines];
52
+ const innerWidth = Math.max(...all.map((l) => stripAnsi(l).length)) + 2;
53
+ const top = '┌' + '─'.repeat(innerWidth) + '┐';
54
+ const bot = '└' + '─'.repeat(innerWidth) + '┘';
55
+ const mid = all.map((l) => {
56
+ const len = stripAnsi(l).length;
57
+ const pad = ' '.repeat(Math.max(innerWidth - len, 0));
58
+ return '│ ' + l + pad + '│';
59
+ });
60
+ return [top, ...mid, bot].join('\n');
61
+ }
62
+ const STATUS_STYLE = {
63
+ available: (s) => chalk_1.default.green.bold(s),
64
+ taken: (s) => chalk_1.default.red(s),
65
+ invalid: (s) => chalk_1.default.yellow(s),
66
+ ratelimited: (s) => chalk_1.default.magenta(s),
67
+ error: (s) => chalk_1.default.gray(s),
68
+ };
69
+ function statusLabel(status) {
70
+ const fn = STATUS_STYLE[status] || ((s) => s);
71
+ return fn(status.toUpperCase());
72
+ }
73
+ function availableTable(results) {
74
+ const available = results.filter((r) => r.status === 'available');
75
+ if (available.length === 0)
76
+ return chalk_1.default.gray('Aucun pseudo disponible trouvé.');
77
+ const table = new cli_table3_1.default({
78
+ head: [
79
+ chalk_1.default.cyan.bold('#'),
80
+ chalk_1.default.cyan.bold('Pseudo'),
81
+ chalk_1.default.cyan.bold('Statut'),
82
+ ],
83
+ colWidths: [6, 26, 16],
84
+ style: { head: [], border: ['gray'] },
85
+ });
86
+ available.forEach((r, i) => {
87
+ table.push([String(i + 1), chalk_1.default.white.bold(r.username), statusLabel(r.status)]);
88
+ });
89
+ return table.toString();
90
+ }
91
+ function summaryLines(stats) {
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}`,
97
+ ` ${chalk_1.default.cyan('Total')} : ${stats.total}`,
98
+ ];
99
+ }
package/package.json ADDED
@@ -0,0 +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"}}