wsnipz 1.2.3 → 1.2.5

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/checker.js CHANGED
@@ -5,21 +5,37 @@ const discord_1 = require("./discord");
5
5
  function sleep(ms) {
6
6
  return new Promise((r) => setTimeout(r, ms));
7
7
  }
8
+ const MAX_RETRIES = 8;
8
9
  async function checkUsernames(usernames, opts) {
9
10
  const results = [];
10
11
  let cursor = 0;
11
12
  let done = 0;
12
13
  const total = usernames.length;
14
+ let globalRateLimitUntil = 0;
13
15
  async function worker() {
14
16
  while (true) {
15
17
  const i = cursor++;
16
18
  if (i >= total)
17
19
  break;
20
+ if (Date.now() < globalRateLimitUntil) {
21
+ await sleep(globalRateLimitUntil - Date.now());
22
+ }
18
23
  const username = usernames[i];
19
24
  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);
25
+ let attempt = 0;
26
+ while ((res.status === 'ratelimited' ||
27
+ (res.status === 'error' && res.retryable)) &&
28
+ attempt < MAX_RETRIES) {
29
+ attempt++;
30
+ if (res.status === 'ratelimited') {
31
+ const retryAfter = res.retryAfter ?? 1;
32
+ const waitMs = Math.min(Math.max(retryAfter * 1000, 1000) * Math.pow(2, attempt - 1), 30000);
33
+ globalRateLimitUntil = Math.max(globalRateLimitUntil, Date.now() + waitMs);
34
+ await sleep(waitMs);
35
+ }
36
+ else {
37
+ await sleep(500 * attempt);
38
+ }
23
39
  res = await (0, discord_1.checkUsername)(username, opts.token, opts.pool);
24
40
  }
25
41
  const result = {
package/dist/discord.js CHANGED
@@ -20,7 +20,7 @@ async function checkUsername(username, token, pool) {
20
20
  headers: { ...DEFAULT_HEADERS, Authorization: token },
21
21
  data: { username },
22
22
  validateStatus: () => true,
23
- timeout: 15000,
23
+ timeout: 10000,
24
24
  proxy: false,
25
25
  };
26
26
  const proxyUrl = pool?.next() ?? undefined;
@@ -31,37 +31,42 @@ async function checkUsername(username, token, pool) {
31
31
  }
32
32
  try {
33
33
  const res = await axios_1.default.request(config);
34
+ if (proxyUrl)
35
+ pool?.markSuccess(proxyUrl);
34
36
  if (res.status === 204 || res.status === 200) {
35
37
  if (res.data?.taken === true) {
36
- return { status: 'taken', message: 'Username already taken' };
38
+ return { status: 'taken', message: 'Username already taken', proxyUsed: proxyUrl };
37
39
  }
38
- return { status: 'available' };
40
+ return { status: 'available', proxyUsed: proxyUrl };
39
41
  }
40
42
  if (res.status === 429) {
41
43
  const retryAfter = Number(res.data?.retry_after ?? 1);
42
- return { status: 'ratelimited', retryAfter: isNaN(retryAfter) ? 1 : retryAfter };
44
+ return { status: 'ratelimited', retryAfter: isNaN(retryAfter) ? 1 : retryAfter, proxyUsed: proxyUrl };
43
45
  }
44
46
  if (res.status === 400) {
45
47
  if (res.data?.taken === true) {
46
- return { status: 'taken', message: 'Username already taken' };
48
+ return { status: 'taken', message: 'Username already taken', proxyUsed: proxyUrl };
47
49
  }
48
50
  const usernameErrors = res.data?.errors?.username?._errors || [];
49
51
  const codes = usernameErrors.map((e) => e.code).filter(Boolean);
50
52
  if (codes.includes('USERNAME_TOO_MANY_RESULTS')) {
51
- return { status: 'taken', message: 'Username already taken' };
53
+ return { status: 'taken', message: 'Username already taken', proxyUsed: proxyUrl };
52
54
  }
53
55
  if (codes.length > 0) {
54
- return { status: 'invalid', message: codes.join(', ') };
56
+ return { status: 'invalid', message: codes.join(', '), proxyUsed: proxyUrl };
55
57
  }
56
- return { status: 'invalid', message: 'Invalid format' };
58
+ return { status: 'invalid', message: 'Invalid format', proxyUsed: proxyUrl };
57
59
  }
58
60
  if (res.status === 401 || res.status === 403) {
59
- return { status: 'error', message: `Invalid token (${res.status})` };
61
+ return { status: 'error', message: `Invalid token (${res.status})`, proxyUsed: proxyUrl };
60
62
  }
61
- return { status: 'error', message: `HTTP ${res.status}` };
63
+ return { status: 'error', message: `HTTP ${res.status}`, proxyUsed: proxyUrl };
62
64
  }
63
65
  catch (err) {
64
- return { status: 'error', message: err?.code || err?.message || 'Network error' };
66
+ if (proxyUrl)
67
+ pool?.markFailed(proxyUrl);
68
+ const code = err?.code || err?.message || 'Network error';
69
+ return { status: 'error', message: code, retryable: true, proxyUsed: proxyUrl };
65
70
  }
66
71
  }
67
72
  async function validateToken(token, pool) {
@@ -5,6 +5,7 @@ exports.charsetFor = charsetFor;
5
5
  exports.patternLabel = patternLabel;
6
6
  exports.generateUsernames = generateUsernames;
7
7
  exports.maxUniqueFor = maxUniqueFor;
8
+ exports.generateAllCombinations = generateAllCombinations;
8
9
  exports.LETTERS = 'abcdefghijklmnopqrstuvwxyz';
9
10
  exports.DIGITS = '0123456789';
10
11
  exports.SPECIAL = '._';
@@ -17,12 +18,12 @@ const PATTERN_SETS = {
17
18
  'digits+special': exports.DIGITS + exports.SPECIAL,
18
19
  };
19
20
  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',
21
+ 'letters': 'Letters (a-z)',
22
+ 'digits': 'Digits (0-9)',
23
+ 'letters+digits': 'Letters + Digits',
24
+ 'letters+special': 'Letters + Special characters (._)',
25
+ 'letters+digits+special': 'Letters + Digits + Special characters',
26
+ 'digits+special': 'Digits + Special characters',
26
27
  };
27
28
  function charsetFor(pattern) {
28
29
  return PATTERN_SETS[pattern];
@@ -57,3 +58,23 @@ function maxUniqueFor(pattern, length) {
57
58
  const charset = charsetFor(pattern);
58
59
  return Math.pow(charset.length, length);
59
60
  }
61
+ function generateAllCombinations(pattern, length) {
62
+ const charset = charsetFor(pattern);
63
+ const out = [];
64
+ const indices = new Array(length).fill(0);
65
+ const total = maxUniqueFor(pattern, length);
66
+ for (let n = 0; n < total; n++) {
67
+ let name = '';
68
+ for (let i = 0; i < length; i++) {
69
+ name += charset[indices[i]];
70
+ }
71
+ out.push(name);
72
+ for (let i = length - 1; i >= 0; i--) {
73
+ indices[i]++;
74
+ if (indices[i] < charset.length)
75
+ break;
76
+ indices[i] = 0;
77
+ }
78
+ }
79
+ return out;
80
+ }
package/dist/prompts.js CHANGED
@@ -179,17 +179,6 @@ async function runChecker(config, save) {
179
179
  validate: (v) => v >= 2 && v <= maxLen ? true : `Between 2 and ${maxLen}`,
180
180
  });
181
181
  const maxUnique = (0, generators_1.maxUniqueFor)(pattern, length);
182
- const { count } = await inquirer_1.default.prompt({
183
- type: 'number',
184
- name: 'count',
185
- message: 'How many usernames to check?',
186
- default: 50,
187
- validate: (v) => v >= 1 && v <= 100000 ? true : 'Between 1 and 100000',
188
- });
189
- const effectiveCount = Math.min(count, maxUnique);
190
- if (effectiveCount < count) {
191
- console.log(chalk_1.default.yellow(` Only ${maxUnique} possible combinations for "${(0, generators_1.patternLabel)(pattern)}" of length ${length}.`));
192
- }
193
182
  const token = await ensureToken(config, save);
194
183
  const pool = await ensureProxyPool(config);
195
184
  save(config);
@@ -197,18 +186,22 @@ async function runChecker(config, save) {
197
186
  type: 'number',
198
187
  name: 'concurrency',
199
188
  message: 'Concurrency (simultaneous requests):',
200
- default: pool && pool.size > 0 ? Math.min(pool.size, 10) : 1,
189
+ default: pool && pool.size > 0 ? Math.min(pool.size, 5) : 1,
201
190
  validate: (v) => (v >= 1 && v <= 100 ? true : 'Between 1 and 100'),
202
191
  });
203
192
  const { delay } = await inquirer_1.default.prompt({
204
193
  type: 'number',
205
194
  name: 'delay',
206
195
  message: 'Delay between requests (ms):',
207
- default: 0,
196
+ default: pool && pool.size > 0 ? 200 : 800,
208
197
  validate: (v) => v >= 0 ? true : '>= 0',
209
198
  });
210
- const usernames = (0, generators_1.generateUsernames)(pattern, length, effectiveCount);
211
- console.log(chalk_1.default.cyan(`\nGenerating ${usernames.length} usernames (${(0, generators_1.patternLabel)(pattern)}, length ${length})...`));
199
+ const comboSpinner = (0, ora_1.default)({ text: 'Creating the combolist...', spinner: 'dots' }).start();
200
+ const usernames = (0, generators_1.generateAllCombinations)(pattern, length);
201
+ const comboFile = `combolist_${Date.now()}.txt`;
202
+ fs_1.default.writeFileSync(comboFile, usernames.join('\n'), 'utf-8');
203
+ comboSpinner.succeed(chalk_1.default.green(`Combolist created: ${chalk_1.default.bold(comboFile)} `) +
204
+ chalk_1.default.gray(`(${usernames.length} combinations)`));
212
205
  const stats = { available: 0, taken: 0, invalid: 0, errors: 0, total: usernames.length };
213
206
  const spinner = (0, ora_1.default)({ text: 'Checking...', spinner: 'dots' }).start();
214
207
  const purple = chalk_1.default.hex('#9B59B6').bold;
@@ -269,6 +262,13 @@ async function runChecker(config, save) {
269
262
  const resFile = `results_${stamp}.txt`;
270
263
  fs_1.default.writeFileSync(resFile, results.map((r) => `${r.username}\t${r.status}${r.message ? '\t' + r.message : ''}`).join('\n'), 'utf-8');
271
264
  console.log(chalk_1.default.gray(` Full results: ${resFile}\n`));
265
+ try {
266
+ fs_1.default.unlinkSync(comboFile);
267
+ console.log(chalk_1.default.gray(` Combolist removed: ${comboFile}`));
268
+ }
269
+ catch {
270
+ // ignore deletion errors
271
+ }
272
272
  }
273
273
  async function configureSettings(config, save) {
274
274
  console.log((0, ui_1.box)('Current configuration', [
package/dist/proxies.js CHANGED
@@ -50,6 +50,8 @@ class ProxyPool {
50
50
  constructor(proxies = [], rotating = false) {
51
51
  this.proxies = [];
52
52
  this.index = 0;
53
+ this.failures = new Map();
54
+ this.dead = new Set();
53
55
  this.rotating = false;
54
56
  this.proxies = proxies;
55
57
  this.rotating = rotating;
@@ -57,6 +59,9 @@ class ProxyPool {
57
59
  get size() {
58
60
  return this.proxies.length;
59
61
  }
62
+ get aliveCount() {
63
+ return this.proxies.length - this.dead.size;
64
+ }
60
65
  get list() {
61
66
  return [...this.proxies];
62
67
  }
@@ -73,12 +78,27 @@ class ProxyPool {
73
78
  next() {
74
79
  if (this.proxies.length === 0)
75
80
  return null;
76
- const proxy = this.proxies[this.index % this.proxies.length];
77
- this.index++;
78
- return proxy;
81
+ for (let attempt = 0; attempt < this.proxies.length; attempt++) {
82
+ const proxy = this.proxies[this.index % this.proxies.length];
83
+ this.index++;
84
+ if (!this.dead.has(proxy))
85
+ return proxy;
86
+ }
87
+ return this.proxies.length > 0 ? this.proxies[0] : null;
88
+ }
89
+ markFailed(proxyUrl) {
90
+ const count = (this.failures.get(proxyUrl) ?? 0) + 1;
91
+ this.failures.set(proxyUrl, count);
92
+ if (count >= ProxyPool.MAX_FAILURES) {
93
+ this.dead.add(proxyUrl);
94
+ }
95
+ }
96
+ markSuccess(proxyUrl) {
97
+ this.failures.delete(proxyUrl);
79
98
  }
80
99
  createAgent(proxyUrl) {
81
100
  return new ProxyAgent(proxyUrl);
82
101
  }
83
102
  }
84
103
  exports.ProxyPool = ProxyPool;
104
+ ProxyPool.MAX_FAILURES = 3;
package/dist/version.js CHANGED
@@ -2,4 +2,4 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.VERSION = exports.PACKAGE_NAME = void 0;
4
4
  exports.PACKAGE_NAME = 'wsnipz';
5
- exports.VERSION = '1.2.3';
5
+ exports.VERSION = '1.2.5';
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name": "wsnipz", "version": "1.2.3", "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"}}
1
+ {"name": "wsnipz", "version": "1.2.5", "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"}}