x402-bazaar 3.6.1 → 3.6.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "x402-bazaar",
3
- "version": "3.6.1",
3
+ "version": "3.6.2",
4
4
  "description": "CLI for x402 Bazaar — AI Agent Marketplace. Browse, call, and auto-pay APIs with USDC on Base. One command to connect your agent.",
5
5
  "type": "module",
6
6
  "main": "bin/cli.js",
@@ -1,28 +1,39 @@
1
- import ora from 'ora';
2
- import chalk from 'chalk';
3
- import { log } from '../utils/logger.js';
1
+ import ora from "ora";
2
+ import chalk from "chalk";
3
+ import { log } from "../utils/logger.js";
4
4
 
5
5
  const CATEGORIES = [
6
- 'ai', 'data', 'automation', 'blockchain', 'weather', 'finance',
7
- 'social', 'image', 'video', 'audio', 'search', 'translation', 'other'
6
+ "ai",
7
+ "data",
8
+ "automation",
9
+ "blockchain",
10
+ "weather",
11
+ "finance",
12
+ "social",
13
+ "image",
14
+ "video",
15
+ "audio",
16
+ "search",
17
+ "translation",
18
+ "other",
8
19
  ];
9
20
 
10
21
  export async function listCommand(options) {
11
- const serverUrl = options.serverUrl || 'https://x402-api.onrender.com';
22
+ const serverUrl = options.serverUrl || "https://x402-api.onrender.com";
12
23
 
13
24
  log.banner();
14
- log.info(`Fetching services from ${chalk.bold('x402 Bazaar')}`);
15
- console.log('');
25
+ log.info(`Fetching services from ${chalk.bold("x402 Bazaar")}`);
26
+ console.log("");
16
27
 
17
28
  // Build query params
18
29
  const params = new URLSearchParams();
19
- if (options.chain) params.append('chain', options.chain);
20
- if (options.category) params.append('category', options.category);
21
- if (options.free) params.append('free', 'true');
30
+ if (options.chain) params.append("chain", options.chain);
31
+ if (options.category) params.append("category", options.category);
32
+ if (options.free) params.append("free", "true");
22
33
 
23
- const url = `${serverUrl}/api/services${params.toString() ? '?' + params.toString() : ''}`;
34
+ const url = `${serverUrl}/api/services${params.toString() ? "?" + params.toString() : ""}`;
24
35
 
25
- const spinner = ora('Loading services...').start();
36
+ const spinner = ora("Loading services...").start();
26
37
 
27
38
  try {
28
39
  const res = await fetch(url, { signal: AbortSignal.timeout(15000) });
@@ -32,94 +43,113 @@ export async function listCommand(options) {
32
43
  }
33
44
 
34
45
  const data = await res.json();
35
- const services = data.services || data || [];
46
+ const services =
47
+ data.data || data.services || (Array.isArray(data) ? data : []);
36
48
 
37
- spinner.succeed(`Found ${chalk.bold(services.length)} service${services.length !== 1 ? 's' : ''}`);
38
- console.log('');
49
+ spinner.succeed(
50
+ `Found ${chalk.bold(services.length)} service${services.length !== 1 ? "s" : ""}`,
51
+ );
52
+ console.log("");
39
53
 
40
54
  if (services.length === 0) {
41
- log.warn('No services found with these filters.');
42
- log.dim(' Try: x402-bazaar list --category ai');
43
- console.log('');
55
+ log.warn("No services found with these filters.");
56
+ log.dim(" Try: x402-bazaar list --category ai");
57
+ console.log("");
44
58
  return;
45
59
  }
46
60
 
47
61
  // Display services table
48
62
  log.separator();
49
- console.log('');
63
+ console.log("");
50
64
 
51
65
  services.forEach((service, idx) => {
52
- const name = service.name || service.title || 'Unnamed Service';
66
+ const name = service.name || service.title || "Unnamed Service";
53
67
  const price = parseFloat(service.price || 0);
54
- const priceLabel = price === 0
55
- ? chalk.hex('#34D399').bold('FREE')
56
- : chalk.cyan(`$${price.toFixed(3)} USDC`);
68
+ const priceLabel =
69
+ price === 0
70
+ ? chalk.hex("#34D399").bold("FREE")
71
+ : chalk.cyan(`$${price.toFixed(3)} USDC`);
57
72
 
58
73
  // Extract category from tags
59
- let category = 'other';
74
+ let category = "other";
60
75
  if (service.tags && Array.isArray(service.tags)) {
61
- const realCategories = service.tags.filter(t => CATEGORIES.includes(t.toLowerCase()));
76
+ const realCategories = service.tags.filter((t) =>
77
+ CATEGORIES.includes(t.toLowerCase()),
78
+ );
62
79
  if (realCategories.length > 0) {
63
80
  category = realCategories[0];
64
81
  }
65
82
  }
66
83
 
67
- const chain = service.chain || 'base';
68
- const chainLabel = chain === 'skale'
69
- ? chalk.hex('#9333EA')('SKALE')
70
- : chalk.hex('#0052FF')('Base');
84
+ const chain = service.chain || "base";
85
+ const chainLabel =
86
+ chain === "skale"
87
+ ? chalk.hex("#9333EA")("SKALE")
88
+ : chalk.hex("#0052FF")("Base");
71
89
 
72
90
  console.log(
73
- chalk.hex('#FF9900').bold(`${(idx + 1).toString().padStart(2, ' ')}. `) +
74
- chalk.white.bold(name)
91
+ chalk
92
+ .hex("#FF9900")
93
+ .bold(`${(idx + 1).toString().padStart(2, " ")}. `) +
94
+ chalk.white.bold(name),
95
+ );
96
+ console.log(
97
+ ` ${priceLabel} ${chalk.dim("|")} ${chalk.hex("#60A5FA")(category)} ${chalk.dim("|")} ${chainLabel}`,
75
98
  );
76
- console.log(` ${priceLabel} ${chalk.dim('|')} ${chalk.hex('#60A5FA')(category)} ${chalk.dim('|')} ${chainLabel}`);
77
99
 
78
100
  if (service.description) {
79
- const desc = service.description.length > 80
80
- ? service.description.substring(0, 77) + '...'
81
- : service.description;
82
- console.log(` ${chalk.hex('#6B7280')(desc)}`);
101
+ const desc =
102
+ service.description.length > 80
103
+ ? service.description.substring(0, 77) + "..."
104
+ : service.description;
105
+ console.log(` ${chalk.hex("#6B7280")(desc)}`);
83
106
  }
84
107
 
85
108
  if (service.endpoint) {
86
- console.log(` ${chalk.dim('Endpoint:')} ${chalk.hex('#FBBF24')(service.endpoint)}`);
109
+ console.log(
110
+ ` ${chalk.dim("Endpoint:")} ${chalk.hex("#FBBF24")(service.endpoint)}`,
111
+ );
87
112
  }
88
113
 
89
- console.log('');
114
+ console.log("");
90
115
  });
91
116
 
92
117
  log.separator();
93
- console.log('');
94
- log.info(`Total: ${chalk.bold(services.length)} service${services.length !== 1 ? 's' : ''}`);
118
+ console.log("");
119
+ log.info(
120
+ `Total: ${chalk.bold(services.length)} service${services.length !== 1 ? "s" : ""}`,
121
+ );
95
122
 
96
123
  // Show filter info
97
124
  if (options.chain || options.category || options.free) {
98
- console.log('');
99
- log.dim(' Active filters:');
125
+ console.log("");
126
+ log.dim(" Active filters:");
100
127
  if (options.chain) log.dim(` Chain: ${options.chain}`);
101
128
  if (options.category) log.dim(` Category: ${options.category}`);
102
- if (options.free) log.dim(' Price: free only');
103
- log.dim(' Run without options to see all services');
129
+ if (options.free) log.dim(" Price: free only");
130
+ log.dim(" Run without options to see all services");
104
131
  }
105
132
 
106
- console.log('');
107
-
133
+ console.log("");
108
134
  } catch (err) {
109
- spinner.fail('Failed to fetch services');
135
+ spinner.fail("Failed to fetch services");
110
136
 
111
- if (err.name === 'AbortError') {
112
- log.error('Request timeout — server may be sleeping (Render free tier)');
113
- log.dim(' Try again in 30 seconds or check status: npx x402-bazaar status');
114
- } else if (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND') {
115
- log.error('Cannot connect to server');
137
+ if (err.name === "AbortError") {
138
+ log.error("Request timeout — server may be sleeping (Render free tier)");
139
+ log.dim(
140
+ " Try again in 30 seconds or check status: npx x402-bazaar status",
141
+ );
142
+ } else if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
143
+ log.error("Cannot connect to server");
116
144
  log.dim(` Server URL: ${serverUrl}`);
117
- log.dim(' Check your internet connection or try: npx x402-bazaar status');
145
+ log.dim(
146
+ " Check your internet connection or try: npx x402-bazaar status",
147
+ );
118
148
  } else {
119
149
  log.error(err.message);
120
150
  }
121
151
 
122
- console.log('');
152
+ console.log("");
123
153
  process.exit(1);
124
154
  }
125
155
  }
@@ -1,29 +1,40 @@
1
- import ora from 'ora';
2
- import chalk from 'chalk';
3
- import { log } from '../utils/logger.js';
1
+ import ora from "ora";
2
+ import chalk from "chalk";
3
+ import { log } from "../utils/logger.js";
4
4
 
5
5
  const CATEGORIES = [
6
- 'ai', 'data', 'automation', 'blockchain', 'weather', 'finance',
7
- 'social', 'image', 'video', 'audio', 'search', 'translation', 'other'
6
+ "ai",
7
+ "data",
8
+ "automation",
9
+ "blockchain",
10
+ "weather",
11
+ "finance",
12
+ "social",
13
+ "image",
14
+ "video",
15
+ "audio",
16
+ "search",
17
+ "translation",
18
+ "other",
8
19
  ];
9
20
 
10
21
  export async function searchCommand(query, options) {
11
22
  if (!query || query.trim().length === 0) {
12
- log.error('Search query is required');
13
- log.dim(' Usage: x402-bazaar search <query>');
23
+ log.error("Search query is required");
24
+ log.dim(" Usage: x402-bazaar search <query>");
14
25
  log.dim(' Example: x402-bazaar search "weather API"');
15
- console.log('');
26
+ console.log("");
16
27
  process.exit(1);
17
28
  }
18
29
 
19
- const serverUrl = options.serverUrl || 'https://x402-api.onrender.com';
30
+ const serverUrl = options.serverUrl || "https://x402-api.onrender.com";
20
31
 
21
32
  log.banner();
22
33
  log.info(`Searching for: ${chalk.bold(query)}`);
23
- console.log('');
34
+ console.log("");
24
35
 
25
36
  const url = `${serverUrl}/api/services?search=${encodeURIComponent(query)}`;
26
- const spinner = ora('Searching...').start();
37
+ const spinner = ora("Searching...").start();
27
38
 
28
39
  try {
29
40
  const res = await fetch(url, { signal: AbortSignal.timeout(15000) });
@@ -33,88 +44,107 @@ export async function searchCommand(query, options) {
33
44
  }
34
45
 
35
46
  const data = await res.json();
36
- const services = data.services || data || [];
47
+ const services =
48
+ data.data || data.services || (Array.isArray(data) ? data : []);
37
49
 
38
50
  if (services.length === 0) {
39
- spinner.fail('No results found');
40
- console.log('');
51
+ spinner.fail("No results found");
52
+ console.log("");
41
53
  log.warn(`No services match "${query}"`);
42
- log.dim(' Tips:');
43
- log.dim(' • Check your spelling');
54
+ log.dim(" Tips:");
55
+ log.dim(" • Check your spelling");
44
56
  log.dim(' • Try broader keywords (e.g., "AI" instead of "GPT-4")');
45
- log.dim(' • Browse all services: x402-bazaar list');
46
- console.log('');
57
+ log.dim(" • Browse all services: x402-bazaar list");
58
+ console.log("");
47
59
  return;
48
60
  }
49
61
 
50
- spinner.succeed(`Found ${chalk.bold(services.length)} result${services.length !== 1 ? 's' : ''}`);
51
- console.log('');
62
+ spinner.succeed(
63
+ `Found ${chalk.bold(services.length)} result${services.length !== 1 ? "s" : ""}`,
64
+ );
65
+ console.log("");
52
66
 
53
67
  // Display results
54
68
  log.separator();
55
- console.log('');
69
+ console.log("");
56
70
 
57
71
  services.forEach((service, idx) => {
58
- const name = service.name || service.title || 'Unnamed Service';
72
+ const name = service.name || service.title || "Unnamed Service";
59
73
  const price = parseFloat(service.price || 0);
60
- const priceLabel = price === 0
61
- ? chalk.hex('#34D399').bold('FREE')
62
- : chalk.cyan(`$${price.toFixed(3)} USDC`);
74
+ const priceLabel =
75
+ price === 0
76
+ ? chalk.hex("#34D399").bold("FREE")
77
+ : chalk.cyan(`$${price.toFixed(3)} USDC`);
63
78
 
64
79
  // Extract category from tags
65
- let category = 'other';
80
+ let category = "other";
66
81
  if (service.tags && Array.isArray(service.tags)) {
67
- const realCategories = service.tags.filter(t => CATEGORIES.includes(t.toLowerCase()));
82
+ const realCategories = service.tags.filter((t) =>
83
+ CATEGORIES.includes(t.toLowerCase()),
84
+ );
68
85
  if (realCategories.length > 0) {
69
86
  category = realCategories[0];
70
87
  }
71
88
  }
72
89
 
73
- const chain = service.chain || 'base';
74
- const chainLabel = chain === 'skale'
75
- ? chalk.hex('#9333EA')('SKALE')
76
- : chalk.hex('#0052FF')('Base');
90
+ const chain = service.chain || "base";
91
+ const chainLabel =
92
+ chain === "skale"
93
+ ? chalk.hex("#9333EA")("SKALE")
94
+ : chalk.hex("#0052FF")("Base");
77
95
 
78
96
  console.log(
79
- chalk.hex('#FF9900').bold(`${(idx + 1).toString().padStart(2, ' ')}. `) +
80
- chalk.white.bold(name)
97
+ chalk
98
+ .hex("#FF9900")
99
+ .bold(`${(idx + 1).toString().padStart(2, " ")}. `) +
100
+ chalk.white.bold(name),
101
+ );
102
+ console.log(
103
+ ` ${priceLabel} ${chalk.dim("|")} ${chalk.hex("#60A5FA")(category)} ${chalk.dim("|")} ${chainLabel}`,
81
104
  );
82
- console.log(` ${priceLabel} ${chalk.dim('|')} ${chalk.hex('#60A5FA')(category)} ${chalk.dim('|')} ${chainLabel}`);
83
105
 
84
106
  if (service.description) {
85
- const desc = service.description.length > 80
86
- ? service.description.substring(0, 77) + '...'
87
- : service.description;
88
- console.log(` ${chalk.hex('#6B7280')(desc)}`);
107
+ const desc =
108
+ service.description.length > 80
109
+ ? service.description.substring(0, 77) + "..."
110
+ : service.description;
111
+ console.log(` ${chalk.hex("#6B7280")(desc)}`);
89
112
  }
90
113
 
91
114
  if (service.endpoint) {
92
- console.log(` ${chalk.dim('Endpoint:')} ${chalk.hex('#FBBF24')(service.endpoint)}`);
115
+ console.log(
116
+ ` ${chalk.dim("Endpoint:")} ${chalk.hex("#FBBF24")(service.endpoint)}`,
117
+ );
93
118
  }
94
119
 
95
- console.log('');
120
+ console.log("");
96
121
  });
97
122
 
98
123
  log.separator();
99
- console.log('');
100
- log.info(`Total: ${chalk.bold(services.length)} result${services.length !== 1 ? 's' : ''}`);
101
- console.log('');
102
-
124
+ console.log("");
125
+ log.info(
126
+ `Total: ${chalk.bold(services.length)} result${services.length !== 1 ? "s" : ""}`,
127
+ );
128
+ console.log("");
103
129
  } catch (err) {
104
- spinner.fail('Search failed');
130
+ spinner.fail("Search failed");
105
131
 
106
- if (err.name === 'AbortError') {
107
- log.error('Request timeout — server may be sleeping (Render free tier)');
108
- log.dim(' Try again in 30 seconds or check status: npx x402-bazaar status');
109
- } else if (err.code === 'ECONNREFUSED' || err.code === 'ENOTFOUND') {
110
- log.error('Cannot connect to server');
132
+ if (err.name === "AbortError") {
133
+ log.error("Request timeout — server may be sleeping (Render free tier)");
134
+ log.dim(
135
+ " Try again in 30 seconds or check status: npx x402-bazaar status",
136
+ );
137
+ } else if (err.code === "ECONNREFUSED" || err.code === "ENOTFOUND") {
138
+ log.error("Cannot connect to server");
111
139
  log.dim(` Server URL: ${serverUrl}`);
112
- log.dim(' Check your internet connection or try: npx x402-bazaar status');
140
+ log.dim(
141
+ " Check your internet connection or try: npx x402-bazaar status",
142
+ );
113
143
  } else {
114
144
  log.error(err.message);
115
145
  }
116
146
 
117
- console.log('');
147
+ console.log("");
118
148
  process.exit(1);
119
149
  }
120
150
  }
@@ -1,18 +1,18 @@
1
- import ora from 'ora';
2
- import chalk from 'chalk';
3
- import { log } from '../utils/logger.js';
1
+ import ora from "ora";
2
+ import chalk from "chalk";
3
+ import { log } from "../utils/logger.js";
4
4
 
5
5
  export async function statusCommand(options) {
6
- const serverUrl = options.serverUrl || 'https://x402-api.onrender.com';
6
+ const serverUrl = options.serverUrl || "https://x402-api.onrender.com";
7
7
 
8
8
  log.banner();
9
9
  log.info(`Checking connection to ${chalk.bold(serverUrl)}`);
10
10
  log.separator();
11
- console.log('');
11
+ console.log("");
12
12
 
13
13
  // 1. Health check
14
14
  let healthOk = false;
15
- const spinner = ora('Checking /health endpoint...').start();
15
+ const spinner = ora("Checking /health endpoint...").start();
16
16
  try {
17
17
  const res = await fetch(`${serverUrl}/health`);
18
18
  const data = await res.json();
@@ -21,43 +21,46 @@ export async function statusCommand(options) {
21
21
  } catch (err) {
22
22
  spinner.fail(`Cannot reach ${serverUrl}/health`);
23
23
  log.error(` ${err.message}`);
24
- log.dim(' Make sure the server is running and the URL is correct.');
25
- console.log('');
24
+ log.dim(" Make sure the server is running and the URL is correct.");
25
+ console.log("");
26
26
  process.exit(1);
27
27
  }
28
28
 
29
29
  // 2. Root endpoint
30
- const spinner2 = ora('Fetching marketplace info...').start();
30
+ const spinner2 = ora("Fetching marketplace info...").start();
31
31
  try {
32
32
  const res = await fetch(serverUrl);
33
33
  const data = await res.json();
34
- spinner2.succeed(`${data.name} — ${chalk.bold(data.total_services)} services`);
34
+ spinner2.succeed(
35
+ `${data.name} — ${chalk.bold(data.total_services)} services`,
36
+ );
35
37
  } catch (err) {
36
38
  spinner2.fail(`Cannot fetch marketplace info: ${err.message}`);
37
39
  }
38
40
 
39
- // 3. Stats
40
- const spinner3 = ora('Fetching stats...').start();
41
+ // 3. Stats (from public endpoints — /api/stats requires admin auth)
42
+ const spinner3 = ora("Fetching stats...").start();
41
43
  try {
42
- const res = await fetch(`${serverUrl}/api/stats`);
43
- const stats = await res.json();
44
- spinner3.succeed('Stats loaded');
45
- console.log('');
46
- log.dim(` Total services: ${stats.totalServices}`);
47
- log.dim(` Total payments: ${stats.totalPayments}`);
48
- log.dim(` Total revenue: ${stats.totalRevenue} USDC`);
49
- if (stats.walletBalance !== null) {
50
- log.dim(` Wallet balance: ${stats.walletBalance} USDC`);
51
- }
52
- log.dim(` Network: ${stats.network}`);
44
+ const res = await fetch(`${serverUrl}/api/services?limit=0`);
45
+ const svcData = await res.json();
46
+ const total = svcData.pagination?.total ?? svcData.data?.length ?? "?";
47
+ const online = Array.isArray(svcData.data)
48
+ ? svcData.data.filter((s) => s.status === "online").length
49
+ : "?";
50
+ spinner3.succeed("Stats loaded");
51
+ console.log("");
52
+ log.dim(` Total services: ${total}`);
53
+ log.dim(` Online: ${online}`);
54
+ log.dim(` Free tier: 5 calls/day without wallet`);
55
+ log.dim(` Chains: SKALE (gas-free), Base, Polygon`);
53
56
  } catch (err) {
54
57
  spinner3.fail(`Cannot fetch stats: ${err.message}`);
55
58
  }
56
59
 
57
- console.log('');
60
+ console.log("");
58
61
  log.separator();
59
- log.success(chalk.bold('x402 Bazaar is operational!'));
62
+ log.success(chalk.bold("x402 Bazaar is operational!"));
60
63
  log.dim(` Dashboard: ${serverUrl}/dashboard`);
61
64
  log.dim(` Website: https://x402bazaar.org`);
62
- console.log('');
65
+ console.log("");
63
66
  }