@opensea/cli 0.2.0 → 0.3.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/README.md +77 -240
- package/dist/cli.js +110 -38
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +8 -8
- package/dist/index.js +49 -11
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -6,16 +6,21 @@ import { Command as Command10 } from "commander";
|
|
|
6
6
|
// src/client.ts
|
|
7
7
|
var DEFAULT_BASE_URL = "https://api.opensea.io";
|
|
8
8
|
var DEFAULT_GRAPHQL_URL = "https://gql.opensea.io/graphql";
|
|
9
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
9
10
|
var OpenSeaClient = class {
|
|
10
11
|
apiKey;
|
|
11
12
|
baseUrl;
|
|
12
13
|
graphqlUrl;
|
|
13
14
|
defaultChain;
|
|
15
|
+
timeoutMs;
|
|
16
|
+
verbose;
|
|
14
17
|
constructor(config) {
|
|
15
18
|
this.apiKey = config.apiKey;
|
|
16
19
|
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
17
20
|
this.graphqlUrl = config.graphqlUrl ?? DEFAULT_GRAPHQL_URL;
|
|
18
21
|
this.defaultChain = config.chain ?? "ethereum";
|
|
22
|
+
this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
23
|
+
this.verbose = config.verbose ?? false;
|
|
19
24
|
}
|
|
20
25
|
async get(path, params) {
|
|
21
26
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
@@ -26,35 +31,64 @@ var OpenSeaClient = class {
|
|
|
26
31
|
}
|
|
27
32
|
}
|
|
28
33
|
}
|
|
34
|
+
if (this.verbose) {
|
|
35
|
+
console.error(`[verbose] GET ${url.toString()}`);
|
|
36
|
+
}
|
|
29
37
|
const response = await fetch(url.toString(), {
|
|
30
38
|
method: "GET",
|
|
31
39
|
headers: {
|
|
32
40
|
Accept: "application/json",
|
|
33
41
|
"x-api-key": this.apiKey
|
|
34
|
-
}
|
|
42
|
+
},
|
|
43
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
35
44
|
});
|
|
45
|
+
if (this.verbose) {
|
|
46
|
+
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
47
|
+
}
|
|
36
48
|
if (!response.ok) {
|
|
37
49
|
const body = await response.text();
|
|
38
50
|
throw new OpenSeaAPIError(response.status, body, path);
|
|
39
51
|
}
|
|
40
52
|
return response.json();
|
|
41
53
|
}
|
|
42
|
-
async post(path) {
|
|
54
|
+
async post(path, body, params) {
|
|
43
55
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
56
|
+
if (params) {
|
|
57
|
+
for (const [key, value] of Object.entries(params)) {
|
|
58
|
+
if (value !== void 0 && value !== null) {
|
|
59
|
+
url.searchParams.set(key, String(value));
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
const headers = {
|
|
64
|
+
Accept: "application/json",
|
|
65
|
+
"x-api-key": this.apiKey
|
|
66
|
+
};
|
|
67
|
+
if (body) {
|
|
68
|
+
headers["Content-Type"] = "application/json";
|
|
69
|
+
}
|
|
70
|
+
if (this.verbose) {
|
|
71
|
+
console.error(`[verbose] POST ${url.toString()}`);
|
|
72
|
+
}
|
|
44
73
|
const response = await fetch(url.toString(), {
|
|
45
74
|
method: "POST",
|
|
46
|
-
headers
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
}
|
|
75
|
+
headers,
|
|
76
|
+
body: body ? JSON.stringify(body) : void 0,
|
|
77
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
50
78
|
});
|
|
79
|
+
if (this.verbose) {
|
|
80
|
+
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
81
|
+
}
|
|
51
82
|
if (!response.ok) {
|
|
52
|
-
const
|
|
53
|
-
throw new OpenSeaAPIError(response.status,
|
|
83
|
+
const text = await response.text();
|
|
84
|
+
throw new OpenSeaAPIError(response.status, text, path);
|
|
54
85
|
}
|
|
55
86
|
return response.json();
|
|
56
87
|
}
|
|
57
88
|
async graphql(query, variables) {
|
|
89
|
+
if (this.verbose) {
|
|
90
|
+
console.error(`[verbose] POST ${this.graphqlUrl}`);
|
|
91
|
+
}
|
|
58
92
|
const response = await fetch(this.graphqlUrl, {
|
|
59
93
|
method: "POST",
|
|
60
94
|
headers: {
|
|
@@ -62,8 +96,12 @@ var OpenSeaClient = class {
|
|
|
62
96
|
Accept: "application/json",
|
|
63
97
|
"x-api-key": this.apiKey
|
|
64
98
|
},
|
|
65
|
-
body: JSON.stringify({ query, variables })
|
|
99
|
+
body: JSON.stringify({ query, variables }),
|
|
100
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
66
101
|
});
|
|
102
|
+
if (this.verbose) {
|
|
103
|
+
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
104
|
+
}
|
|
67
105
|
if (!response.ok) {
|
|
68
106
|
const body = await response.text();
|
|
69
107
|
throw new OpenSeaAPIError(response.status, body, "graphql");
|
|
@@ -130,6 +168,7 @@ function formatTable(data) {
|
|
|
130
168
|
}
|
|
131
169
|
if (data && typeof data === "object") {
|
|
132
170
|
const entries = Object.entries(data);
|
|
171
|
+
if (entries.length === 0) return "(empty)";
|
|
133
172
|
const maxKeyLength = Math.max(...entries.map(([k]) => k.length));
|
|
134
173
|
return entries.map(([key, value]) => {
|
|
135
174
|
const displayValue = typeof value === "object" && value !== null ? JSON.stringify(value) : String(value ?? "");
|
|
@@ -152,6 +191,24 @@ function accountsCommand(getClient2, getFormat2) {
|
|
|
152
191
|
|
|
153
192
|
// src/commands/collections.ts
|
|
154
193
|
import { Command as Command2 } from "commander";
|
|
194
|
+
|
|
195
|
+
// src/parse.ts
|
|
196
|
+
function parseIntOption(value, name) {
|
|
197
|
+
const parsed = Number.parseInt(value, 10);
|
|
198
|
+
if (Number.isNaN(parsed)) {
|
|
199
|
+
throw new Error(`Invalid value for ${name}: "${value}" is not an integer`);
|
|
200
|
+
}
|
|
201
|
+
return parsed;
|
|
202
|
+
}
|
|
203
|
+
function parseFloatOption(value, name) {
|
|
204
|
+
const parsed = Number.parseFloat(value);
|
|
205
|
+
if (Number.isNaN(parsed)) {
|
|
206
|
+
throw new Error(`Invalid value for ${name}: "${value}" is not a number`);
|
|
207
|
+
}
|
|
208
|
+
return parsed;
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
// src/commands/collections.ts
|
|
155
212
|
function collectionsCommand(getClient2, getFormat2) {
|
|
156
213
|
const cmd = new Command2("collections").description(
|
|
157
214
|
"Manage and query NFT collections"
|
|
@@ -172,7 +229,7 @@ function collectionsCommand(getClient2, getFormat2) {
|
|
|
172
229
|
order_by: options.orderBy,
|
|
173
230
|
creator_username: options.creator,
|
|
174
231
|
include_hidden: options.includeHidden,
|
|
175
|
-
limit:
|
|
232
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
176
233
|
next: options.next
|
|
177
234
|
});
|
|
178
235
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -207,10 +264,10 @@ function eventsCommand(getClient2, getFormat2) {
|
|
|
207
264
|
const client = getClient2();
|
|
208
265
|
const result = await client.get("/api/v2/events", {
|
|
209
266
|
event_type: options.eventType,
|
|
210
|
-
after: options.after ?
|
|
211
|
-
before: options.before ?
|
|
267
|
+
after: options.after ? parseIntOption(options.after, "--after") : void 0,
|
|
268
|
+
before: options.before ? parseIntOption(options.before, "--before") : void 0,
|
|
212
269
|
chain: options.chain,
|
|
213
|
-
limit:
|
|
270
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
214
271
|
next: options.next
|
|
215
272
|
});
|
|
216
273
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -222,7 +279,7 @@ function eventsCommand(getClient2, getFormat2) {
|
|
|
222
279
|
const result = await client.get(`/api/v2/events/accounts/${address}`, {
|
|
223
280
|
event_type: options.eventType,
|
|
224
281
|
chain: options.chain,
|
|
225
|
-
limit:
|
|
282
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
226
283
|
next: options.next
|
|
227
284
|
});
|
|
228
285
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -233,7 +290,7 @@ function eventsCommand(getClient2, getFormat2) {
|
|
|
233
290
|
const client = getClient2();
|
|
234
291
|
const result = await client.get(`/api/v2/events/collection/${slug}`, {
|
|
235
292
|
event_type: options.eventType,
|
|
236
|
-
limit:
|
|
293
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
237
294
|
next: options.next
|
|
238
295
|
});
|
|
239
296
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -246,7 +303,7 @@ function eventsCommand(getClient2, getFormat2) {
|
|
|
246
303
|
`/api/v2/events/chain/${chain}/contract/${contract}/nfts/${tokenId}`,
|
|
247
304
|
{
|
|
248
305
|
event_type: options.eventType,
|
|
249
|
-
limit:
|
|
306
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
250
307
|
next: options.next
|
|
251
308
|
}
|
|
252
309
|
);
|
|
@@ -264,7 +321,7 @@ function listingsCommand(getClient2, getFormat2) {
|
|
|
264
321
|
async (collection, options) => {
|
|
265
322
|
const client = getClient2();
|
|
266
323
|
const result = await client.get(`/api/v2/listings/collection/${collection}/all`, {
|
|
267
|
-
limit:
|
|
324
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
268
325
|
next: options.next
|
|
269
326
|
});
|
|
270
327
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -274,7 +331,7 @@ function listingsCommand(getClient2, getFormat2) {
|
|
|
274
331
|
async (collection, options) => {
|
|
275
332
|
const client = getClient2();
|
|
276
333
|
const result = await client.get(`/api/v2/listings/collection/${collection}/best`, {
|
|
277
|
-
limit:
|
|
334
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
278
335
|
next: options.next
|
|
279
336
|
});
|
|
280
337
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -306,7 +363,7 @@ function nftsCommand(getClient2, getFormat2) {
|
|
|
306
363
|
const result = await client.get(
|
|
307
364
|
`/api/v2/collection/${slug}/nfts`,
|
|
308
365
|
{
|
|
309
|
-
limit:
|
|
366
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
310
367
|
next: options.next
|
|
311
368
|
}
|
|
312
369
|
);
|
|
@@ -318,7 +375,7 @@ function nftsCommand(getClient2, getFormat2) {
|
|
|
318
375
|
const result = await client.get(
|
|
319
376
|
`/api/v2/chain/${chain}/contract/${contract}/nfts`,
|
|
320
377
|
{
|
|
321
|
-
limit:
|
|
378
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
322
379
|
next: options.next
|
|
323
380
|
}
|
|
324
381
|
);
|
|
@@ -331,7 +388,7 @@ function nftsCommand(getClient2, getFormat2) {
|
|
|
331
388
|
const result = await client.get(
|
|
332
389
|
`/api/v2/chain/${chain}/account/${address}/nfts`,
|
|
333
390
|
{
|
|
334
|
-
limit:
|
|
391
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
335
392
|
next: options.next
|
|
336
393
|
}
|
|
337
394
|
);
|
|
@@ -368,7 +425,7 @@ function offersCommand(getClient2, getFormat2) {
|
|
|
368
425
|
async (collection, options) => {
|
|
369
426
|
const client = getClient2();
|
|
370
427
|
const result = await client.get(`/api/v2/offers/collection/${collection}/all`, {
|
|
371
|
-
limit:
|
|
428
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
372
429
|
next: options.next
|
|
373
430
|
});
|
|
374
431
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -378,7 +435,7 @@ function offersCommand(getClient2, getFormat2) {
|
|
|
378
435
|
async (collection, options) => {
|
|
379
436
|
const client = getClient2();
|
|
380
437
|
const result = await client.get(`/api/v2/offers/collection/${collection}`, {
|
|
381
|
-
limit:
|
|
438
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
382
439
|
next: options.next
|
|
383
440
|
});
|
|
384
441
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -397,7 +454,7 @@ function offersCommand(getClient2, getFormat2) {
|
|
|
397
454
|
const result = await client.get(`/api/v2/offers/collection/${collection}/traits`, {
|
|
398
455
|
type: options.type,
|
|
399
456
|
value: options.value,
|
|
400
|
-
limit:
|
|
457
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
401
458
|
next: options.next
|
|
402
459
|
});
|
|
403
460
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -512,7 +569,7 @@ function searchCommand(getClient2, getFormat2) {
|
|
|
512
569
|
const client = getClient2();
|
|
513
570
|
const result = await client.graphql(SEARCH_COLLECTIONS_QUERY, {
|
|
514
571
|
query,
|
|
515
|
-
limit:
|
|
572
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
516
573
|
chains: options.chains?.split(",")
|
|
517
574
|
});
|
|
518
575
|
console.log(formatOutput(result.collectionsByQuery, getFormat2()));
|
|
@@ -524,7 +581,7 @@ function searchCommand(getClient2, getFormat2) {
|
|
|
524
581
|
const result = await client.graphql(SEARCH_NFTS_QUERY, {
|
|
525
582
|
query,
|
|
526
583
|
collectionSlug: options.collection,
|
|
527
|
-
limit:
|
|
584
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
528
585
|
chains: options.chains?.split(",")
|
|
529
586
|
});
|
|
530
587
|
console.log(formatOutput(result.itemsByQuery, getFormat2()));
|
|
@@ -535,7 +592,7 @@ function searchCommand(getClient2, getFormat2) {
|
|
|
535
592
|
const client = getClient2();
|
|
536
593
|
const result = await client.graphql(SEARCH_TOKENS_QUERY, {
|
|
537
594
|
query,
|
|
538
|
-
limit:
|
|
595
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
539
596
|
chain: options.chain
|
|
540
597
|
});
|
|
541
598
|
console.log(formatOutput(result.currenciesByQuery, getFormat2()));
|
|
@@ -545,7 +602,7 @@ function searchCommand(getClient2, getFormat2) {
|
|
|
545
602
|
const client = getClient2();
|
|
546
603
|
const result = await client.graphql(SEARCH_ACCOUNTS_QUERY, {
|
|
547
604
|
query,
|
|
548
|
-
limit:
|
|
605
|
+
limit: parseIntOption(options.limit, "--limit")
|
|
549
606
|
});
|
|
550
607
|
console.log(formatOutput(result.accountsByQuery, getFormat2()));
|
|
551
608
|
});
|
|
@@ -584,7 +641,7 @@ function swapsCommand(getClient2, getFormat2) {
|
|
|
584
641
|
to_address: options.toAddress,
|
|
585
642
|
quantity: options.quantity,
|
|
586
643
|
address: options.address,
|
|
587
|
-
slippage: options.slippage ?
|
|
644
|
+
slippage: options.slippage ? parseFloatOption(options.slippage, "--slippage") : void 0,
|
|
588
645
|
recipient: options.recipient
|
|
589
646
|
}
|
|
590
647
|
);
|
|
@@ -600,29 +657,31 @@ function tokensCommand(getClient2, getFormat2) {
|
|
|
600
657
|
const cmd = new Command9("tokens").description(
|
|
601
658
|
"Query trending tokens, top tokens, and token details"
|
|
602
659
|
);
|
|
603
|
-
cmd.command("trending").description("Get trending tokens based on OpenSea's trending score").option("--chains <chains>", "Comma-separated list of chains to filter by").option("--limit <limit>", "Number of results (max 100)", "20").option("--
|
|
660
|
+
cmd.command("trending").description("Get trending tokens based on OpenSea's trending score").option("--chains <chains>", "Comma-separated list of chains to filter by").option("--limit <limit>", "Number of results (max 100)", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
604
661
|
async (options) => {
|
|
605
662
|
const client = getClient2();
|
|
606
663
|
const result = await client.get(
|
|
607
664
|
"/api/v2/tokens/trending",
|
|
608
665
|
{
|
|
609
666
|
chains: options.chains,
|
|
610
|
-
limit:
|
|
611
|
-
cursor
|
|
667
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
668
|
+
// Tokens API uses "cursor" instead of "next" as the query param
|
|
669
|
+
cursor: options.next
|
|
612
670
|
}
|
|
613
671
|
);
|
|
614
672
|
console.log(formatOutput(result, getFormat2()));
|
|
615
673
|
}
|
|
616
674
|
);
|
|
617
|
-
cmd.command("top").description("Get top tokens ranked by 24-hour trading volume").option("--chains <chains>", "Comma-separated list of chains to filter by").option("--limit <limit>", "Number of results (max 100)", "20").option("--
|
|
675
|
+
cmd.command("top").description("Get top tokens ranked by 24-hour trading volume").option("--chains <chains>", "Comma-separated list of chains to filter by").option("--limit <limit>", "Number of results (max 100)", "20").option("--next <cursor>", "Pagination cursor").action(
|
|
618
676
|
async (options) => {
|
|
619
677
|
const client = getClient2();
|
|
620
678
|
const result = await client.get(
|
|
621
679
|
"/api/v2/tokens/top",
|
|
622
680
|
{
|
|
623
681
|
chains: options.chains,
|
|
624
|
-
limit:
|
|
625
|
-
cursor
|
|
682
|
+
limit: parseIntOption(options.limit, "--limit"),
|
|
683
|
+
// Tokens API uses "cursor" instead of "next" as the query param
|
|
684
|
+
cursor: options.next
|
|
626
685
|
}
|
|
627
686
|
);
|
|
628
687
|
console.log(formatOutput(result, getFormat2()));
|
|
@@ -650,7 +709,7 @@ var BANNER = `
|
|
|
650
709
|
|_|
|
|
651
710
|
`;
|
|
652
711
|
var program = new Command10();
|
|
653
|
-
program.name("opensea").description("OpenSea CLI - Query the OpenSea API from the command line").version(process.env.npm_package_version ?? "0.0.0").addHelpText("before", BANNER).option("--api-key <key>", "OpenSea API key (or set OPENSEA_API_KEY env var)").option("--chain <chain>", "Default chain", "ethereum").option("--format <format>", "Output format (json or table)", "json").option("--base-url <url>", "API base URL");
|
|
712
|
+
program.name("opensea").description("OpenSea CLI - Query the OpenSea API from the command line").version(process.env.npm_package_version ?? "0.0.0").addHelpText("before", BANNER).option("--api-key <key>", "OpenSea API key (or set OPENSEA_API_KEY env var)").option("--chain <chain>", "Default chain", "ethereum").option("--format <format>", "Output format (json or table)", "json").option("--base-url <url>", "API base URL").option("--timeout <ms>", "Request timeout in milliseconds", "30000").option("--verbose", "Log request and response info to stderr");
|
|
654
713
|
function getClient() {
|
|
655
714
|
const opts = program.opts();
|
|
656
715
|
const apiKey = opts.apiKey ?? process.env.OPENSEA_API_KEY;
|
|
@@ -663,7 +722,9 @@ function getClient() {
|
|
|
663
722
|
return new OpenSeaClient({
|
|
664
723
|
apiKey,
|
|
665
724
|
chain: opts.chain,
|
|
666
|
-
baseUrl: opts.baseUrl
|
|
725
|
+
baseUrl: opts.baseUrl,
|
|
726
|
+
timeout: parseIntOption(opts.timeout, "--timeout"),
|
|
727
|
+
verbose: opts.verbose
|
|
667
728
|
});
|
|
668
729
|
}
|
|
669
730
|
function getFormat() {
|
|
@@ -698,7 +759,18 @@ async function main() {
|
|
|
698
759
|
);
|
|
699
760
|
process.exit(1);
|
|
700
761
|
}
|
|
701
|
-
|
|
762
|
+
const label = error instanceof TypeError ? "Network Error" : error.name;
|
|
763
|
+
console.error(
|
|
764
|
+
JSON.stringify(
|
|
765
|
+
{
|
|
766
|
+
error: label,
|
|
767
|
+
message: error.message
|
|
768
|
+
},
|
|
769
|
+
null,
|
|
770
|
+
2
|
|
771
|
+
)
|
|
772
|
+
);
|
|
773
|
+
process.exit(1);
|
|
702
774
|
}
|
|
703
775
|
}
|
|
704
776
|
main();
|