recker 1.0.7 → 1.0.8

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/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  ### The HTTP SDK for the AI Era
8
8
 
9
- **Stop fetching. Start orchestrating.**
9
+ **Fast as infrastructure demands. AI-ready from the first byte. Observable down to the millisecond. Resilient when everything else fails.**
10
10
 
11
11
  [![npm version](https://img.shields.io/npm/v/recker.svg?style=flat-square&color=F5A623)](https://www.npmjs.com/package/recker)
12
12
  [![npm downloads](https://img.shields.io/npm/dm/recker.svg?style=flat-square&color=34C759)](https://www.npmjs.com/package/recker)
@@ -102,24 +102,24 @@ console.log(timings);
102
102
 
103
103
  **Getting Started**
104
104
  - [Installation](./docs/getting-started/installation.md)
105
- - [Quick Start](./docs/getting-started/quickstart.md)
106
- - [Client Configuration](./docs/guides/client-config.md)
105
+ - [Quick Start](./docs/http/01-quickstart.md)
106
+ - [Client Configuration](./docs/http/05-configuration.md)
107
107
 
108
108
  **Core Features**
109
- - [HTTP Methods (19)](./docs/guides/http-methods.md)
110
- - [Streaming & SSE](./docs/guides/streaming.md)
111
- - [Retry & Backoff](./docs/guides/advanced/retry.md)
112
- - [Caching](./docs/guides/caching.md)
113
- - [Pagination](./docs/guides/pagination.md)
109
+ - [HTTP Fundamentals](./docs/http/02-fundamentals.md)
110
+ - [Streaming & SSE](./docs/ai/02-streaming.md)
111
+ - [Retry & Resilience](./docs/http/07-resilience.md)
112
+ - [Caching](./docs/http/09-cache.md)
113
+ - [Concurrency](./docs/http/08-concurrency.md)
114
114
 
115
115
  **Integrations**
116
- - [GraphQL](./docs/guides/graphql.md)
117
- - [Scraping](./docs/guides/scraping.md)
118
- - [Hooks](./docs/guides/hooks.md)
116
+ - [GraphQL](./docs/http/13-graphql.md)
117
+ - [Scraping](./docs/http/14-scraping.md)
118
+ - [Plugins](./docs/http/10-plugins.md)
119
119
 
120
120
  **Reference**
121
- - [API Reference](./docs/api/README.md)
122
- - [Troubleshooting](./docs/guides/troubleshooting.md)
121
+ - [API Reference](./docs/reference/01-api.md)
122
+ - [Troubleshooting](./docs/reference/05-troubleshooting.md)
123
123
  - [Examples](./docs/examples/README.md)
124
124
 
125
125
  ## ❤️ Acknowledgements
@@ -1 +1 @@
1
- {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/cli/handler.ts"],"names":[],"mappings":"AAmBA,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,GAAG,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,iBAqG1D"}
1
+ {"version":3,"file":"handler.d.ts","sourceRoot":"","sources":["../../src/cli/handler.ts"],"names":[],"mappings":"AAwBA,UAAU,cAAc;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAChC,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,GAAG,CAAC;CACpB;AAED,wBAAsB,aAAa,CAAC,OAAO,EAAE,cAAc,iBAqG1D"}
@@ -6,8 +6,13 @@ let highlight;
6
6
  const ora = oraImport;
7
7
  async function initDependencies() {
8
8
  if (!highlight) {
9
- const cardinal = await requireOptional('cardinal', 'recker/cli');
10
- highlight = cardinal.highlight;
9
+ try {
10
+ const cardinal = await requireOptional('cardinal', 'recker/cli');
11
+ highlight = cardinal.highlight;
12
+ }
13
+ catch {
14
+ highlight = (code) => code;
15
+ }
11
16
  }
12
17
  }
13
18
  export async function handleRequest(options) {
@@ -22,6 +22,11 @@ export declare class RekShell {
22
22
  private resolveVariables;
23
23
  private resolveUrl;
24
24
  private executeRequest;
25
+ private runWhois;
26
+ private runTLS;
27
+ private runDNS;
28
+ private runRDAP;
29
+ private runPing;
25
30
  private printHelp;
26
31
  }
27
32
  //# sourceMappingURL=shell.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/shell.ts"],"names":[],"mappings":"AAsBA,qBAAa,QAAQ;IACnB,OAAO,CAAC,EAAE,CAAsB;IAChC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,WAAW,CAAS;;YAWd,iBAAiB;IAe/B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,SAAS;IAMJ,KAAK;IA8BlB,OAAO,CAAC,MAAM;YAKA,aAAa;YAgGb,kBAAkB;YAkBlB,SAAS;YAkBT,WAAW;IA0DzB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,UAAU;YAeJ,cAAc;IAyE5B,OAAO,CAAC,SAAS;CAwClB"}
1
+ {"version":3,"file":"shell.d.ts","sourceRoot":"","sources":["../../../src/cli/tui/shell.ts"],"names":[],"mappings":"AAgCA,qBAAa,QAAQ;IACnB,OAAO,CAAC,EAAE,CAAsB;IAChC,OAAO,CAAC,MAAM,CAAM;IACpB,OAAO,CAAC,OAAO,CAAqB;IACpC,OAAO,CAAC,OAAO,CAAc;IAC7B,OAAO,CAAC,YAAY,CAAa;IACjC,OAAO,CAAC,SAAS,CAA2B;IAC5C,OAAO,CAAC,WAAW,CAAS;;YAWd,iBAAiB;IAe/B,OAAO,CAAC,SAAS;IAKjB,OAAO,CAAC,SAAS;IAWJ,KAAK;IA8BlB,OAAO,CAAC,MAAM;YAKA,aAAa;YAgHb,kBAAkB;YAkBlB,SAAS;YAkBT,WAAW;IA0DzB,OAAO,CAAC,SAAS;IAMjB,OAAO,CAAC,UAAU;IAMlB,OAAO,CAAC,WAAW;IASnB,OAAO,CAAC,gBAAgB;IAoBxB,OAAO,CAAC,UAAU;YAeJ,cAAc;YAyEd,QAAQ;YA8CR,MAAM;YAuDN,MAAM;YAuEN,OAAO;YA2DP,OAAO;IAoCrB,OAAO,CAAC,SAAS;CA+ClB"}
@@ -1,13 +1,23 @@
1
1
  import readline from 'node:readline';
2
+ import { promises as dns } from 'node:dns';
2
3
  import { requireOptional } from '../../utils/optional-require.js';
3
4
  import { createClient } from '../../core/client.js';
4
5
  import { startInteractiveWebSocket } from './websocket.js';
6
+ import { whois, isDomainAvailable } from '../../utils/whois.js';
7
+ import { inspectTLS } from '../../utils/tls-inspector.js';
8
+ import { getSecurityRecords } from '../../utils/dns-toolkit.js';
9
+ import { rdap } from '../../utils/rdap.js';
5
10
  import pc from '../../utils/colors.js';
6
11
  let highlight;
7
12
  async function initDependencies() {
8
13
  if (!highlight) {
9
- const cardinal = await requireOptional('cardinal', 'recker/cli');
10
- highlight = cardinal.highlight;
14
+ try {
15
+ const cardinal = await requireOptional('cardinal', 'recker/cli');
16
+ highlight = cardinal.highlight;
17
+ }
18
+ catch {
19
+ highlight = (code) => code;
20
+ }
11
21
  }
12
22
  }
13
23
  export class RekShell {
@@ -41,7 +51,12 @@ export class RekShell {
41
51
  return `${base} ${pc.magenta('›')} `;
42
52
  }
43
53
  completer(line) {
44
- const commands = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'ws', 'udp', 'load', 'chat', 'ai', 'help', 'clear', 'exit', 'set', 'url'];
54
+ const commands = [
55
+ 'get', 'post', 'put', 'delete', 'patch', 'head', 'options',
56
+ 'ws', 'udp', 'load', 'chat', 'ai',
57
+ 'whois', 'tls', 'ssl', 'dns', 'rdap', 'ping',
58
+ 'help', 'clear', 'exit', 'set', 'url', 'vars'
59
+ ];
45
60
  const hits = commands.filter((c) => c.startsWith(line));
46
61
  return [hits.length ? hits : commands, line];
47
62
  }
@@ -104,6 +119,22 @@ export class RekShell {
104
119
  case 'chat':
105
120
  await this.runAIChat(parts.slice(1));
106
121
  return;
122
+ case 'whois':
123
+ await this.runWhois(parts[1]);
124
+ return;
125
+ case 'tls':
126
+ case 'ssl':
127
+ await this.runTLS(parts[1], parts[2] ? parseInt(parts[2]) : 443);
128
+ return;
129
+ case 'dns':
130
+ await this.runDNS(parts[1]);
131
+ return;
132
+ case 'rdap':
133
+ await this.runRDAP(parts[1]);
134
+ return;
135
+ case 'ping':
136
+ await this.runPing(parts[1]);
137
+ return;
107
138
  }
108
139
  const methods = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options'];
109
140
  let method = 'GET';
@@ -343,6 +374,216 @@ export class RekShell {
343
374
  }
344
375
  console.log('');
345
376
  }
377
+ async runWhois(domain) {
378
+ if (!domain) {
379
+ console.log(pc.yellow('Usage: whois <domain>'));
380
+ console.log(pc.gray(' Examples: whois google.com | whois 8.8.8.8'));
381
+ return;
382
+ }
383
+ console.log(pc.gray(`Looking up ${domain}...`));
384
+ const startTime = performance.now();
385
+ try {
386
+ const result = await whois(domain);
387
+ const duration = Math.round(performance.now() - startTime);
388
+ console.log(pc.green(`✔ WHOIS lookup completed`) + pc.gray(` (${duration}ms)`));
389
+ console.log(pc.gray(`Server: ${result.server}\n`));
390
+ const importantFields = [
391
+ 'domain name', 'registrar', 'registrar url',
392
+ 'creation date', 'registry expiry date', 'updated date',
393
+ 'domain status', 'name server', 'dnssec',
394
+ 'organization', 'orgname', 'cidr', 'netname', 'country'
395
+ ];
396
+ for (const field of importantFields) {
397
+ const value = result.data[field];
398
+ if (value) {
399
+ const displayValue = Array.isArray(value) ? value.join(', ') : value;
400
+ console.log(` ${pc.cyan(field)}: ${displayValue}`);
401
+ }
402
+ }
403
+ const available = await isDomainAvailable(domain);
404
+ if (available) {
405
+ console.log(pc.green(`\n✓ Domain appears to be available`));
406
+ }
407
+ this.lastResponse = result.data;
408
+ }
409
+ catch (error) {
410
+ console.error(pc.red(`WHOIS failed: ${error.message}`));
411
+ }
412
+ console.log('');
413
+ }
414
+ async runTLS(host, port = 443) {
415
+ if (!host) {
416
+ console.log(pc.yellow('Usage: tls <host> [port]'));
417
+ console.log(pc.gray(' Examples: tls google.com | tls api.stripe.com 443'));
418
+ return;
419
+ }
420
+ host = host.replace(/^https?:\/\//, '').split('/')[0];
421
+ console.log(pc.gray(`Inspecting TLS for ${host}:${port}...`));
422
+ const startTime = performance.now();
423
+ try {
424
+ const info = await inspectTLS(host, port);
425
+ const duration = Math.round(performance.now() - startTime);
426
+ const statusIcon = info.valid ? pc.green('✔') : pc.red('✖');
427
+ const statusText = info.valid ? pc.green('Valid') : pc.red('Invalid/Expired');
428
+ console.log(`${statusIcon} Certificate ${statusText}` + pc.gray(` (${duration}ms)\n`));
429
+ console.log(pc.bold(' Certificate:'));
430
+ console.log(` ${pc.cyan('Subject')}: ${info.subject?.CN || info.subject?.O || 'N/A'}`);
431
+ console.log(` ${pc.cyan('Issuer')}: ${info.issuer?.CN || info.issuer?.O || 'N/A'}`);
432
+ console.log(` ${pc.cyan('Valid From')}: ${info.validFrom.toISOString()}`);
433
+ console.log(` ${pc.cyan('Valid To')}: ${info.validTo.toISOString()}`);
434
+ const daysColor = info.daysRemaining < 30 ? pc.red : info.daysRemaining < 90 ? pc.yellow : pc.green;
435
+ console.log(` ${pc.cyan('Days Remaining')}: ${daysColor(String(info.daysRemaining))}`);
436
+ console.log(pc.bold('\n Connection:'));
437
+ console.log(` ${pc.cyan('Protocol')}: ${info.protocol || 'N/A'}`);
438
+ console.log(` ${pc.cyan('Cipher')}: ${info.cipher?.name || 'N/A'}`);
439
+ console.log(` ${pc.cyan('Authorized')}: ${info.authorized ? pc.green('Yes') : pc.red('No')}`);
440
+ if (info.authorizationError) {
441
+ console.log(` ${pc.cyan('Auth Error')}: ${pc.red(String(info.authorizationError))}`);
442
+ }
443
+ console.log(pc.bold('\n Fingerprints:'));
444
+ console.log(` ${pc.cyan('SHA1')}: ${info.fingerprint}`);
445
+ console.log(` ${pc.cyan('SHA256')}: ${info.fingerprint256}`);
446
+ console.log(` ${pc.cyan('Serial')}: ${info.serialNumber}`);
447
+ this.lastResponse = info;
448
+ }
449
+ catch (error) {
450
+ console.error(pc.red(`TLS inspection failed: ${error.message}`));
451
+ }
452
+ console.log('');
453
+ }
454
+ async runDNS(domain) {
455
+ if (!domain) {
456
+ console.log(pc.yellow('Usage: dns <domain>'));
457
+ console.log(pc.gray(' Examples: dns google.com | dns github.com'));
458
+ return;
459
+ }
460
+ console.log(pc.gray(`Resolving DNS for ${domain}...`));
461
+ const startTime = performance.now();
462
+ try {
463
+ const [a, aaaa, mx, ns, txt, security] = await Promise.all([
464
+ dns.resolve4(domain).catch(() => []),
465
+ dns.resolve6(domain).catch(() => []),
466
+ dns.resolveMx(domain).catch(() => []),
467
+ dns.resolveNs(domain).catch(() => []),
468
+ dns.resolveTxt(domain).catch(() => []),
469
+ getSecurityRecords(domain).catch(() => ({}))
470
+ ]);
471
+ const duration = Math.round(performance.now() - startTime);
472
+ console.log(pc.green(`✔ DNS resolved`) + pc.gray(` (${duration}ms)\n`));
473
+ if (a.length) {
474
+ console.log(pc.bold(' A Records (IPv4):'));
475
+ a.forEach(ip => console.log(` ${pc.cyan('→')} ${ip}`));
476
+ }
477
+ if (aaaa.length) {
478
+ console.log(pc.bold(' AAAA Records (IPv6):'));
479
+ aaaa.forEach(ip => console.log(` ${pc.cyan('→')} ${ip}`));
480
+ }
481
+ if (ns.length) {
482
+ console.log(pc.bold(' NS Records:'));
483
+ ns.forEach(n => console.log(` ${pc.cyan('→')} ${n}`));
484
+ }
485
+ if (mx.length) {
486
+ console.log(pc.bold(' MX Records:'));
487
+ mx.sort((a, b) => a.priority - b.priority)
488
+ .forEach(m => console.log(` ${pc.cyan(String(m.priority).padStart(3))} ${m.exchange}`));
489
+ }
490
+ const sec = security;
491
+ if (sec.spf?.length) {
492
+ console.log(pc.bold(' SPF:'));
493
+ console.log(` ${pc.gray(sec.spf[0].slice(0, 80))}${sec.spf[0].length > 80 ? '...' : ''}`);
494
+ }
495
+ if (sec.dmarc) {
496
+ console.log(pc.bold(' DMARC:'));
497
+ console.log(` ${pc.gray(sec.dmarc.slice(0, 80))}${sec.dmarc.length > 80 ? '...' : ''}`);
498
+ }
499
+ if (sec.caa?.issue?.length) {
500
+ console.log(pc.bold(' CAA:'));
501
+ sec.caa.issue.forEach((ca) => console.log(` ${pc.cyan('issue')} ${ca}`));
502
+ }
503
+ this.lastResponse = { a, aaaa, mx, ns, txt, security };
504
+ }
505
+ catch (error) {
506
+ console.error(pc.red(`DNS lookup failed: ${error.message}`));
507
+ }
508
+ console.log('');
509
+ }
510
+ async runRDAP(domain) {
511
+ if (!domain) {
512
+ console.log(pc.yellow('Usage: rdap <domain>'));
513
+ console.log(pc.gray(' Examples: rdap google.com | rdap 8.8.8.8'));
514
+ return;
515
+ }
516
+ console.log(pc.gray(`RDAP lookup for ${domain}...`));
517
+ const startTime = performance.now();
518
+ try {
519
+ const result = await rdap(this.client, domain);
520
+ const duration = Math.round(performance.now() - startTime);
521
+ console.log(pc.green(`✔ RDAP lookup completed`) + pc.gray(` (${duration}ms)\n`));
522
+ if (result.status?.length) {
523
+ console.log(pc.bold(' Status:'));
524
+ result.status.forEach((s) => console.log(` ${pc.cyan('→')} ${s}`));
525
+ }
526
+ if (result.events?.length) {
527
+ console.log(pc.bold(' Events:'));
528
+ result.events.forEach((e) => {
529
+ const date = new Date(e.eventDate).toISOString().split('T')[0];
530
+ console.log(` ${pc.cyan(e.eventAction.padEnd(15))} ${date}`);
531
+ });
532
+ }
533
+ if (result.entities?.length) {
534
+ console.log(pc.bold(' Entities:'));
535
+ result.entities.forEach((e) => {
536
+ const roles = e.roles?.join(', ') || 'unknown';
537
+ console.log(` ${pc.cyan(roles.padEnd(15))} ${e.handle || 'N/A'}`);
538
+ });
539
+ }
540
+ if (result.handle) {
541
+ console.log(` ${pc.cyan('Handle')}: ${result.handle}`);
542
+ }
543
+ if (result.name) {
544
+ console.log(` ${pc.cyan('Name')}: ${result.name}`);
545
+ }
546
+ if (result.startAddress && result.endAddress) {
547
+ console.log(` ${pc.cyan('Range')}: ${result.startAddress} - ${result.endAddress}`);
548
+ }
549
+ this.lastResponse = result;
550
+ }
551
+ catch (error) {
552
+ console.error(pc.red(`RDAP lookup failed: ${error.message}`));
553
+ console.log(pc.gray(' Tip: RDAP may not be available for all TLDs. Try "whois" instead.'));
554
+ }
555
+ console.log('');
556
+ }
557
+ async runPing(host) {
558
+ if (!host) {
559
+ console.log(pc.yellow('Usage: ping <host>'));
560
+ return;
561
+ }
562
+ host = host.replace(/^https?:\/\//, '').split('/')[0];
563
+ console.log(pc.gray(`Pinging ${host}...`));
564
+ try {
565
+ const { connect } = await import('node:net');
566
+ const port = 443;
567
+ const startTime = performance.now();
568
+ await new Promise((resolve, reject) => {
569
+ const socket = connect(port, host, () => {
570
+ const duration = Math.round(performance.now() - startTime);
571
+ console.log(pc.green(`✔ ${host}:${port} is reachable`) + pc.gray(` (${duration}ms)`));
572
+ socket.end();
573
+ resolve();
574
+ });
575
+ socket.on('error', reject);
576
+ socket.setTimeout(5000, () => {
577
+ socket.destroy();
578
+ reject(new Error('Connection timed out'));
579
+ });
580
+ });
581
+ }
582
+ catch (error) {
583
+ console.error(pc.red(`✖ ${host} is unreachable: ${error.message}`));
584
+ }
585
+ console.log('');
586
+ }
346
587
  printHelp() {
347
588
  console.log(`
348
589
  ${pc.bold(pc.cyan('Rek Console Help'))}
@@ -375,6 +616,13 @@ export class RekShell {
375
616
  ${pc.green('ws <url>')} Start interactive WebSocket session.
376
617
  ${pc.green('udp <url>')} Send UDP packet.
377
618
 
619
+ ${pc.bold('Network Tools:')}
620
+ ${pc.green('whois <domain>')} WHOIS lookup (domain or IP).
621
+ ${pc.green('tls <host> [port]')} Inspect TLS/SSL certificate.
622
+ ${pc.green('dns <domain>')} Full DNS lookup (A, AAAA, MX, NS, SPF, DMARC).
623
+ ${pc.green('rdap <domain>')} RDAP lookup (modern WHOIS).
624
+ ${pc.green('ping <host>')} Quick TCP connectivity check.
625
+
378
626
  ${pc.bold('Examples:')}
379
627
  › url httpbin.org
380
628
  › get /json
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "recker",
3
- "version": "1.0.7",
3
+ "version": "1.0.8",
4
4
  "description": "AI & DevX focused HTTP client for Node.js 18+",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",