-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathcli.ts
More file actions
151 lines (139 loc) · 4.29 KB
/
cli.ts
File metadata and controls
151 lines (139 loc) · 4.29 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
import { Command } from "commander"
import { OpenSeaAPIError, OpenSeaClient } from "./client.js"
import {
accountsCommand,
collectionsCommand,
eventsCommand,
healthCommand,
listingsCommand,
nftsCommand,
offersCommand,
searchCommand,
swapsCommand,
tokensCommand,
} from "./commands/index.js"
import type { OutputFilterOptions, OutputFormat } from "./output.js"
import { parseIntOption } from "./parse.js"
const EXIT_API_ERROR = 1
const EXIT_AUTH_ERROR = 2
const EXIT_RATE_LIMITED = 3
const BANNER = `
____ _____
/ __ \\ / ____|
| | | |_ __ ___ _ _| (___ ___ __ _
| | | | '_ \\ / _ \\ '_ \\___ \\ / _ \\/ _\` |
| |__| | |_) | __/ | | |___) | __/ (_| |
\\____/| .__/ \\___|_| |_|____/ \\___|\\__,_|
| |
|_|
`
const program = new Command()
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, table, or toon)", "json")
.option("--base-url <url>", "API base URL")
.option("--timeout <ms>", "Request timeout in milliseconds", "30000")
.option("--retries <n>", "Max retries on 429/5xx errors", "3")
.option("--verbose", "Log request and response info to stderr")
.option(
"--fields <fields>",
"Comma-separated list of fields to include in output",
)
.option("--max-items <n>", "Truncate array output to first N items")
function getClient(): OpenSeaClient {
const opts = program.opts<{
apiKey?: string
chain: string
baseUrl?: string
timeout: string
retries: string
verbose?: boolean
}>()
const apiKey = opts.apiKey ?? process.env.OPENSEA_API_KEY
if (!apiKey) {
console.error(
"Error: API key required. Use --api-key or set OPENSEA_API_KEY environment variable.",
)
process.exit(EXIT_AUTH_ERROR)
}
return new OpenSeaClient({
apiKey,
chain: opts.chain,
baseUrl: opts.baseUrl,
timeout: parseIntOption(opts.timeout, "--timeout"),
retries: parseIntOption(opts.retries, "--retries"),
verbose: opts.verbose,
})
}
function getFormat(): OutputFormat {
const opts = program.opts<{ format: string }>()
if (opts.format === "table") return "table"
if (opts.format === "toon") return "toon"
return "json"
}
function getFilters(): OutputFilterOptions {
const opts = program.opts<{
fields?: string
maxItems?: string
}>()
return {
fields: opts.fields
?.split(",")
.map(f => f.trim())
.filter(Boolean),
maxItems: opts.maxItems
? parseIntOption(opts.maxItems, "--max-items")
: undefined,
}
}
program.addCommand(collectionsCommand(getClient, getFormat, getFilters))
program.addCommand(nftsCommand(getClient, getFormat, getFilters))
program.addCommand(listingsCommand(getClient, getFormat, getFilters))
program.addCommand(offersCommand(getClient, getFormat, getFilters))
program.addCommand(eventsCommand(getClient, getFormat, getFilters))
program.addCommand(accountsCommand(getClient, getFormat, getFilters))
program.addCommand(tokensCommand(getClient, getFormat, getFilters))
program.addCommand(searchCommand(getClient, getFormat, getFilters))
program.addCommand(swapsCommand(getClient, getFormat, getFilters))
program.addCommand(healthCommand(getClient))
async function main() {
try {
await program.parseAsync(process.argv)
} catch (error) {
if (error instanceof OpenSeaAPIError) {
const isRateLimited = error.statusCode === 429
console.error(
JSON.stringify(
{
error: isRateLimited ? "Rate Limited" : "API Error",
status: error.statusCode,
path: error.path,
message: error.responseBody,
},
null,
2,
),
)
process.exit(isRateLimited ? EXIT_RATE_LIMITED : EXIT_API_ERROR)
}
const label =
error instanceof TypeError ? "Network Error" : (error as Error).name
console.error(
JSON.stringify(
{
error: label,
message: (error as Error).message,
},
null,
2,
),
)
process.exit(EXIT_API_ERROR)
}
}
main()