@opensea/cli 0.3.0 → 0.4.1
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 +28 -1
- package/dist/cli.js +295 -174
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +45 -90
- package/dist/index.js +306 -143
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -89,7 +89,7 @@ opensea --format table collections stats mfers
|
|
|
89
89
|
| `swaps` | Get swap quotes for token trading |
|
|
90
90
|
| `accounts` | Get account details |
|
|
91
91
|
|
|
92
|
-
Global options: `--api-key`, `--chain` (default: ethereum), `--format` (json/table), `--base-url`
|
|
92
|
+
Global options: `--api-key`, `--chain` (default: ethereum), `--format` (json/table/toon), `--base-url`
|
|
93
93
|
|
|
94
94
|
Full command reference with all options and flags: [docs/cli-reference.md](docs/cli-reference.md)
|
|
95
95
|
|
|
@@ -137,6 +137,33 @@ Table - human-readable output:
|
|
|
137
137
|
opensea --format table collections list --limit 5
|
|
138
138
|
```
|
|
139
139
|
|
|
140
|
+
TOON - [Token-Oriented Object Notation](https://github.com/toon-format/toon), a compact format that uses ~40% fewer tokens than JSON. Ideal for piping output into LLM / AI agent context windows:
|
|
141
|
+
|
|
142
|
+
```bash
|
|
143
|
+
opensea --format toon tokens trending --limit 5
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Example TOON output for a list of tokens:
|
|
147
|
+
|
|
148
|
+
```
|
|
149
|
+
tokens[3]{name,symbol,chain,market_cap,price_usd}:
|
|
150
|
+
Ethereum,ETH,ethereum,250000000000,2100.50
|
|
151
|
+
Bitcoin,BTC,bitcoin,900000000000,48000.00
|
|
152
|
+
Solana,SOL,solana,30000000000,95.25
|
|
153
|
+
next: abc123
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
TOON collapses uniform arrays of objects into CSV-like tables with a single header row, while nested objects use YAML-like indentation. The encoder follows the [TOON v3.0 spec](https://github.com/toon-format/spec/blob/main/SPEC.md) and is implemented without external dependencies.
|
|
157
|
+
|
|
158
|
+
TOON is also available programmatically via the SDK:
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
import { formatToon } from "@opensea/cli"
|
|
162
|
+
|
|
163
|
+
const data = await client.tokens.trending({ limit: 5 })
|
|
164
|
+
console.log(formatToon(data))
|
|
165
|
+
```
|
|
166
|
+
|
|
140
167
|
## Exit Codes
|
|
141
168
|
|
|
142
169
|
- `0` - Success
|
package/dist/cli.js
CHANGED
|
@@ -5,19 +5,16 @@ import { Command as Command10 } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// src/client.ts
|
|
7
7
|
var DEFAULT_BASE_URL = "https://api.opensea.io";
|
|
8
|
-
var DEFAULT_GRAPHQL_URL = "https://gql.opensea.io/graphql";
|
|
9
8
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
10
9
|
var OpenSeaClient = class {
|
|
11
10
|
apiKey;
|
|
12
11
|
baseUrl;
|
|
13
|
-
graphqlUrl;
|
|
14
12
|
defaultChain;
|
|
15
13
|
timeoutMs;
|
|
16
14
|
verbose;
|
|
17
15
|
constructor(config) {
|
|
18
16
|
this.apiKey = config.apiKey;
|
|
19
17
|
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
20
|
-
this.graphqlUrl = config.graphqlUrl ?? DEFAULT_GRAPHQL_URL;
|
|
21
18
|
this.defaultChain = config.chain ?? "ethereum";
|
|
22
19
|
this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
23
20
|
this.verbose = config.verbose ?? false;
|
|
@@ -85,40 +82,6 @@ var OpenSeaClient = class {
|
|
|
85
82
|
}
|
|
86
83
|
return response.json();
|
|
87
84
|
}
|
|
88
|
-
async graphql(query, variables) {
|
|
89
|
-
if (this.verbose) {
|
|
90
|
-
console.error(`[verbose] POST ${this.graphqlUrl}`);
|
|
91
|
-
}
|
|
92
|
-
const response = await fetch(this.graphqlUrl, {
|
|
93
|
-
method: "POST",
|
|
94
|
-
headers: {
|
|
95
|
-
"Content-Type": "application/json",
|
|
96
|
-
Accept: "application/json",
|
|
97
|
-
"x-api-key": this.apiKey
|
|
98
|
-
},
|
|
99
|
-
body: JSON.stringify({ query, variables }),
|
|
100
|
-
signal: AbortSignal.timeout(this.timeoutMs)
|
|
101
|
-
});
|
|
102
|
-
if (this.verbose) {
|
|
103
|
-
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
104
|
-
}
|
|
105
|
-
if (!response.ok) {
|
|
106
|
-
const body = await response.text();
|
|
107
|
-
throw new OpenSeaAPIError(response.status, body, "graphql");
|
|
108
|
-
}
|
|
109
|
-
const json = await response.json();
|
|
110
|
-
if (json.errors?.length) {
|
|
111
|
-
throw new OpenSeaAPIError(
|
|
112
|
-
400,
|
|
113
|
-
json.errors.map((e) => e.message).join("; "),
|
|
114
|
-
"graphql"
|
|
115
|
-
);
|
|
116
|
-
}
|
|
117
|
-
if (!json.data) {
|
|
118
|
-
throw new OpenSeaAPIError(500, "GraphQL response missing data", "graphql");
|
|
119
|
-
}
|
|
120
|
-
return json.data;
|
|
121
|
-
}
|
|
122
85
|
getDefaultChain() {
|
|
123
86
|
return this.defaultChain;
|
|
124
87
|
}
|
|
@@ -136,11 +99,284 @@ var OpenSeaAPIError = class extends Error {
|
|
|
136
99
|
// src/commands/accounts.ts
|
|
137
100
|
import { Command } from "commander";
|
|
138
101
|
|
|
102
|
+
// src/toon.ts
|
|
103
|
+
var INDENT = " ";
|
|
104
|
+
var NUMERIC_RE = /^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i;
|
|
105
|
+
var LEADING_ZERO_RE = /^0\d+$/;
|
|
106
|
+
var UNQUOTED_KEY_RE = /^[A-Za-z_][A-Za-z0-9_.]*$/;
|
|
107
|
+
function escapeString(s) {
|
|
108
|
+
return s.replace(/\\/g, "\\\\").replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/\t/g, "\\t");
|
|
109
|
+
}
|
|
110
|
+
function needsQuoting(value, delimiter) {
|
|
111
|
+
if (value === "") return true;
|
|
112
|
+
if (value !== value.trim()) return true;
|
|
113
|
+
if (value === "true" || value === "false" || value === "null") return true;
|
|
114
|
+
if (NUMERIC_RE.test(value) || LEADING_ZERO_RE.test(value)) return true;
|
|
115
|
+
if (/[:"\\[\]{}]/.test(value)) return true;
|
|
116
|
+
if (/[\n\r\t]/.test(value)) return true;
|
|
117
|
+
if (value.includes(delimiter)) return true;
|
|
118
|
+
if (value.startsWith("-")) return true;
|
|
119
|
+
return false;
|
|
120
|
+
}
|
|
121
|
+
function encodeKey(key) {
|
|
122
|
+
if (UNQUOTED_KEY_RE.test(key)) return key;
|
|
123
|
+
return `"${escapeString(key)}"`;
|
|
124
|
+
}
|
|
125
|
+
function encodePrimitive(value, delimiter) {
|
|
126
|
+
if (value === null) return "null";
|
|
127
|
+
if (value === void 0) return "null";
|
|
128
|
+
if (typeof value === "boolean") return String(value);
|
|
129
|
+
if (typeof value === "number") return String(value);
|
|
130
|
+
if (typeof value === "string") {
|
|
131
|
+
if (needsQuoting(value, delimiter)) {
|
|
132
|
+
return `"${escapeString(value)}"`;
|
|
133
|
+
}
|
|
134
|
+
return value;
|
|
135
|
+
}
|
|
136
|
+
return `"${escapeString(String(value))}"`;
|
|
137
|
+
}
|
|
138
|
+
function isPrimitive(value) {
|
|
139
|
+
return value === null || value === void 0 || typeof value === "boolean" || typeof value === "number" || typeof value === "string";
|
|
140
|
+
}
|
|
141
|
+
function isTabular(arr) {
|
|
142
|
+
if (arr.length === 0) return false;
|
|
143
|
+
const first = arr[0];
|
|
144
|
+
if (first === null || typeof first !== "object" || Array.isArray(first))
|
|
145
|
+
return false;
|
|
146
|
+
const keys = Object.keys(first).sort();
|
|
147
|
+
for (const item of arr) {
|
|
148
|
+
if (item === null || typeof item !== "object" || Array.isArray(item))
|
|
149
|
+
return false;
|
|
150
|
+
const itemKeys = Object.keys(item).sort();
|
|
151
|
+
if (itemKeys.length !== keys.length) return false;
|
|
152
|
+
for (let i = 0; i < keys.length; i++) {
|
|
153
|
+
if (itemKeys[i] !== keys[i]) return false;
|
|
154
|
+
}
|
|
155
|
+
for (const k of keys) {
|
|
156
|
+
if (!isPrimitive(item[k])) return false;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return true;
|
|
160
|
+
}
|
|
161
|
+
function isPrimitiveArray(arr) {
|
|
162
|
+
return arr.every(isPrimitive);
|
|
163
|
+
}
|
|
164
|
+
function encodeValue(value, depth, delimiter) {
|
|
165
|
+
if (isPrimitive(value)) {
|
|
166
|
+
return encodePrimitive(value, delimiter);
|
|
167
|
+
}
|
|
168
|
+
if (Array.isArray(value)) {
|
|
169
|
+
return encodeArray(value, depth, delimiter);
|
|
170
|
+
}
|
|
171
|
+
if (typeof value === "object" && value !== null) {
|
|
172
|
+
return encodeObject(value, depth, delimiter);
|
|
173
|
+
}
|
|
174
|
+
return encodePrimitive(value, delimiter);
|
|
175
|
+
}
|
|
176
|
+
function encodeObject(obj, depth, delimiter) {
|
|
177
|
+
const entries = Object.entries(obj);
|
|
178
|
+
if (entries.length === 0) return "";
|
|
179
|
+
const lines = [];
|
|
180
|
+
const prefix = INDENT.repeat(depth);
|
|
181
|
+
for (const [key, value] of entries) {
|
|
182
|
+
const encodedKey = encodeKey(key);
|
|
183
|
+
if (isPrimitive(value)) {
|
|
184
|
+
lines.push(`${prefix}${encodedKey}: ${encodePrimitive(value, delimiter)}`);
|
|
185
|
+
} else if (Array.isArray(value)) {
|
|
186
|
+
lines.push(encodeArrayField(encodedKey, value, depth, delimiter));
|
|
187
|
+
} else if (typeof value === "object" && value !== null) {
|
|
188
|
+
const nested = value;
|
|
189
|
+
if (Object.keys(nested).length === 0) {
|
|
190
|
+
lines.push(`${prefix}${encodedKey}:`);
|
|
191
|
+
} else {
|
|
192
|
+
lines.push(`${prefix}${encodedKey}:`);
|
|
193
|
+
lines.push(encodeObject(nested, depth + 1, delimiter));
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return lines.join("\n");
|
|
198
|
+
}
|
|
199
|
+
function encodeArrayField(encodedKey, arr, depth, delimiter) {
|
|
200
|
+
const prefix = INDENT.repeat(depth);
|
|
201
|
+
if (arr.length === 0) {
|
|
202
|
+
return `${prefix}${encodedKey}[0]:`;
|
|
203
|
+
}
|
|
204
|
+
if (isPrimitiveArray(arr)) {
|
|
205
|
+
const values = arr.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
206
|
+
return `${prefix}${encodedKey}[${arr.length}]: ${values}`;
|
|
207
|
+
}
|
|
208
|
+
if (isTabular(arr)) {
|
|
209
|
+
const firstObj = arr[0];
|
|
210
|
+
const fields = Object.keys(firstObj);
|
|
211
|
+
const fieldHeader = fields.map(encodeKey).join(delimiter);
|
|
212
|
+
const lines = [];
|
|
213
|
+
lines.push(`${prefix}${encodedKey}[${arr.length}]{${fieldHeader}}:`);
|
|
214
|
+
const rowPrefix = INDENT.repeat(depth + 1);
|
|
215
|
+
for (const item of arr) {
|
|
216
|
+
const obj = item;
|
|
217
|
+
const row = fields.map((f) => encodePrimitive(obj[f], delimiter)).join(delimiter);
|
|
218
|
+
lines.push(`${rowPrefix}${row}`);
|
|
219
|
+
}
|
|
220
|
+
return lines.join("\n");
|
|
221
|
+
}
|
|
222
|
+
return encodeExpandedList(encodedKey, arr, depth, delimiter);
|
|
223
|
+
}
|
|
224
|
+
function encodeExpandedList(encodedKey, arr, depth, delimiter) {
|
|
225
|
+
const prefix = INDENT.repeat(depth);
|
|
226
|
+
const itemPrefix = INDENT.repeat(depth + 1);
|
|
227
|
+
const lines = [];
|
|
228
|
+
lines.push(`${prefix}${encodedKey}[${arr.length}]:`);
|
|
229
|
+
for (const item of arr) {
|
|
230
|
+
if (isPrimitive(item)) {
|
|
231
|
+
lines.push(`${itemPrefix}- ${encodePrimitive(item, delimiter)}`);
|
|
232
|
+
} else if (Array.isArray(item)) {
|
|
233
|
+
if (isPrimitiveArray(item)) {
|
|
234
|
+
const values = item.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
235
|
+
lines.push(`${itemPrefix}- [${item.length}]: ${values}`);
|
|
236
|
+
} else {
|
|
237
|
+
lines.push(`${itemPrefix}- [${item.length}]:`);
|
|
238
|
+
for (const inner of item) {
|
|
239
|
+
lines.push(encodeValue(inner, depth + 2, delimiter));
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
} else if (typeof item === "object" && item !== null) {
|
|
243
|
+
const obj = item;
|
|
244
|
+
const entries = Object.entries(obj);
|
|
245
|
+
if (entries.length === 0) {
|
|
246
|
+
lines.push(`${itemPrefix}-`);
|
|
247
|
+
} else {
|
|
248
|
+
const [firstKey, firstValue] = entries[0];
|
|
249
|
+
const ek = encodeKey(firstKey);
|
|
250
|
+
if (Array.isArray(firstValue)) {
|
|
251
|
+
const arrayLine = encodeArrayField(ek, firstValue, 0, delimiter);
|
|
252
|
+
lines.push(`${itemPrefix}- ${arrayLine.trimStart()}`);
|
|
253
|
+
} else if (isPrimitive(firstValue)) {
|
|
254
|
+
lines.push(
|
|
255
|
+
`${itemPrefix}- ${ek}: ${encodePrimitive(firstValue, delimiter)}`
|
|
256
|
+
);
|
|
257
|
+
} else {
|
|
258
|
+
lines.push(`${itemPrefix}- ${ek}:`);
|
|
259
|
+
lines.push(
|
|
260
|
+
encodeObject(
|
|
261
|
+
firstValue,
|
|
262
|
+
depth + 2,
|
|
263
|
+
delimiter
|
|
264
|
+
)
|
|
265
|
+
);
|
|
266
|
+
}
|
|
267
|
+
for (let i = 1; i < entries.length; i++) {
|
|
268
|
+
const [k, v] = entries[i];
|
|
269
|
+
const encodedK = encodeKey(k);
|
|
270
|
+
if (isPrimitive(v)) {
|
|
271
|
+
lines.push(
|
|
272
|
+
`${INDENT.repeat(depth + 2)}${encodedK}: ${encodePrimitive(v, delimiter)}`
|
|
273
|
+
);
|
|
274
|
+
} else if (Array.isArray(v)) {
|
|
275
|
+
lines.push(encodeArrayField(encodedK, v, depth + 2, delimiter));
|
|
276
|
+
} else if (typeof v === "object" && v !== null) {
|
|
277
|
+
lines.push(`${INDENT.repeat(depth + 2)}${encodedK}:`);
|
|
278
|
+
lines.push(
|
|
279
|
+
encodeObject(v, depth + 3, delimiter)
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
return lines.join("\n");
|
|
287
|
+
}
|
|
288
|
+
function encodeArray(arr, depth, delimiter) {
|
|
289
|
+
const prefix = INDENT.repeat(depth);
|
|
290
|
+
if (arr.length === 0) {
|
|
291
|
+
return `${prefix}[0]:`;
|
|
292
|
+
}
|
|
293
|
+
if (isPrimitiveArray(arr)) {
|
|
294
|
+
const values = arr.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
295
|
+
return `${prefix}[${arr.length}]: ${values}`;
|
|
296
|
+
}
|
|
297
|
+
if (isTabular(arr)) {
|
|
298
|
+
const firstObj = arr[0];
|
|
299
|
+
const fields = Object.keys(firstObj);
|
|
300
|
+
const fieldHeader = fields.map(encodeKey).join(delimiter);
|
|
301
|
+
const lines2 = [];
|
|
302
|
+
lines2.push(`${prefix}[${arr.length}]{${fieldHeader}}:`);
|
|
303
|
+
const rowPrefix = INDENT.repeat(depth + 1);
|
|
304
|
+
for (const item of arr) {
|
|
305
|
+
const obj = item;
|
|
306
|
+
const row = fields.map((f) => encodePrimitive(obj[f], delimiter)).join(delimiter);
|
|
307
|
+
lines2.push(`${rowPrefix}${row}`);
|
|
308
|
+
}
|
|
309
|
+
return lines2.join("\n");
|
|
310
|
+
}
|
|
311
|
+
const lines = [];
|
|
312
|
+
lines.push(`${prefix}[${arr.length}]:`);
|
|
313
|
+
const itemPrefix = INDENT.repeat(depth + 1);
|
|
314
|
+
for (const item of arr) {
|
|
315
|
+
if (isPrimitive(item)) {
|
|
316
|
+
lines.push(`${itemPrefix}- ${encodePrimitive(item, delimiter)}`);
|
|
317
|
+
} else if (Array.isArray(item)) {
|
|
318
|
+
if (isPrimitiveArray(item)) {
|
|
319
|
+
const values = item.map((v) => encodePrimitive(v, delimiter)).join(delimiter);
|
|
320
|
+
lines.push(`${itemPrefix}- [${item.length}]: ${values}`);
|
|
321
|
+
} else {
|
|
322
|
+
lines.push(`${itemPrefix}- [${item.length}]:`);
|
|
323
|
+
}
|
|
324
|
+
} else if (typeof item === "object" && item !== null) {
|
|
325
|
+
const obj = item;
|
|
326
|
+
const entries = Object.entries(obj);
|
|
327
|
+
if (entries.length > 0) {
|
|
328
|
+
const [firstKey, firstValue] = entries[0];
|
|
329
|
+
const ek = encodeKey(firstKey);
|
|
330
|
+
if (isPrimitive(firstValue)) {
|
|
331
|
+
lines.push(
|
|
332
|
+
`${itemPrefix}- ${ek}: ${encodePrimitive(firstValue, delimiter)}`
|
|
333
|
+
);
|
|
334
|
+
} else {
|
|
335
|
+
lines.push(`${itemPrefix}- ${ek}:`);
|
|
336
|
+
lines.push(encodeValue(firstValue, depth + 2, delimiter));
|
|
337
|
+
}
|
|
338
|
+
for (let i = 1; i < entries.length; i++) {
|
|
339
|
+
const [k, v] = entries[i];
|
|
340
|
+
const encodedK = encodeKey(k);
|
|
341
|
+
if (isPrimitive(v)) {
|
|
342
|
+
lines.push(
|
|
343
|
+
`${INDENT.repeat(depth + 2)}${encodedK}: ${encodePrimitive(v, delimiter)}`
|
|
344
|
+
);
|
|
345
|
+
} else if (Array.isArray(v)) {
|
|
346
|
+
lines.push(encodeArrayField(encodedK, v, depth + 2, delimiter));
|
|
347
|
+
} else if (typeof v === "object" && v !== null) {
|
|
348
|
+
lines.push(`${INDENT.repeat(depth + 2)}${encodedK}:`);
|
|
349
|
+
lines.push(
|
|
350
|
+
encodeObject(v, depth + 3, delimiter)
|
|
351
|
+
);
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
return lines.join("\n");
|
|
358
|
+
}
|
|
359
|
+
function formatToon(data) {
|
|
360
|
+
if (isPrimitive(data)) {
|
|
361
|
+
return encodePrimitive(data, ",");
|
|
362
|
+
}
|
|
363
|
+
if (Array.isArray(data)) {
|
|
364
|
+
return encodeArray(data, 0, ",");
|
|
365
|
+
}
|
|
366
|
+
if (typeof data === "object" && data !== null) {
|
|
367
|
+
return encodeObject(data, 0, ",");
|
|
368
|
+
}
|
|
369
|
+
return String(data);
|
|
370
|
+
}
|
|
371
|
+
|
|
139
372
|
// src/output.ts
|
|
140
373
|
function formatOutput(data, format) {
|
|
141
374
|
if (format === "table") {
|
|
142
375
|
return formatTable(data);
|
|
143
376
|
}
|
|
377
|
+
if (format === "toon") {
|
|
378
|
+
return formatToon(data);
|
|
379
|
+
}
|
|
144
380
|
return JSON.stringify(data, null, 2);
|
|
145
381
|
}
|
|
146
382
|
function formatTable(data) {
|
|
@@ -465,147 +701,30 @@ function offersCommand(getClient2, getFormat2) {
|
|
|
465
701
|
|
|
466
702
|
// src/commands/search.ts
|
|
467
703
|
import { Command as Command7 } from "commander";
|
|
468
|
-
|
|
469
|
-
// src/queries.ts
|
|
470
|
-
var SEARCH_COLLECTIONS_QUERY = `
|
|
471
|
-
query SearchCollections($query: String!, $limit: Int, $chains: [ChainIdentifier!]) {
|
|
472
|
-
collectionsByQuery(query: $query, limit: $limit, chains: $chains) {
|
|
473
|
-
slug
|
|
474
|
-
name
|
|
475
|
-
description
|
|
476
|
-
imageUrl
|
|
477
|
-
chain {
|
|
478
|
-
identifier
|
|
479
|
-
name
|
|
480
|
-
}
|
|
481
|
-
stats {
|
|
482
|
-
totalSupply
|
|
483
|
-
ownerCount
|
|
484
|
-
volume {
|
|
485
|
-
usd
|
|
486
|
-
}
|
|
487
|
-
sales
|
|
488
|
-
}
|
|
489
|
-
floorPrice {
|
|
490
|
-
pricePerItem {
|
|
491
|
-
usd
|
|
492
|
-
native {
|
|
493
|
-
unit
|
|
494
|
-
symbol
|
|
495
|
-
}
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
}`;
|
|
500
|
-
var SEARCH_NFTS_QUERY = `
|
|
501
|
-
query SearchItems($query: String!, $collectionSlug: String, $limit: Int, $chains: [ChainIdentifier!]) {
|
|
502
|
-
itemsByQuery(query: $query, collectionSlug: $collectionSlug, limit: $limit, chains: $chains) {
|
|
503
|
-
tokenId
|
|
504
|
-
name
|
|
505
|
-
description
|
|
506
|
-
imageUrl
|
|
507
|
-
contractAddress
|
|
508
|
-
collection {
|
|
509
|
-
slug
|
|
510
|
-
name
|
|
511
|
-
}
|
|
512
|
-
chain {
|
|
513
|
-
identifier
|
|
514
|
-
name
|
|
515
|
-
}
|
|
516
|
-
bestListing {
|
|
517
|
-
pricePerItem {
|
|
518
|
-
usd
|
|
519
|
-
native {
|
|
520
|
-
unit
|
|
521
|
-
symbol
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
}
|
|
525
|
-
owner {
|
|
526
|
-
address
|
|
527
|
-
displayName
|
|
528
|
-
}
|
|
529
|
-
}
|
|
530
|
-
}`;
|
|
531
|
-
var SEARCH_TOKENS_QUERY = `
|
|
532
|
-
query SearchCurrencies($query: String!, $limit: Int, $chain: ChainIdentifier) {
|
|
533
|
-
currenciesByQuery(query: $query, limit: $limit, chain: $chain, allowlistOnly: false) {
|
|
534
|
-
name
|
|
535
|
-
symbol
|
|
536
|
-
imageUrl
|
|
537
|
-
usdPrice
|
|
538
|
-
contractAddress
|
|
539
|
-
chain {
|
|
540
|
-
identifier
|
|
541
|
-
name
|
|
542
|
-
}
|
|
543
|
-
stats {
|
|
544
|
-
marketCapUsd
|
|
545
|
-
oneDay {
|
|
546
|
-
priceChange
|
|
547
|
-
volume
|
|
548
|
-
}
|
|
549
|
-
}
|
|
550
|
-
}
|
|
551
|
-
}`;
|
|
552
|
-
var SEARCH_ACCOUNTS_QUERY = `
|
|
553
|
-
query SearchAccounts($query: String!, $limit: Int) {
|
|
554
|
-
accountsByQuery(query: $query, limit: $limit) {
|
|
555
|
-
address
|
|
556
|
-
username
|
|
557
|
-
imageUrl
|
|
558
|
-
isVerified
|
|
559
|
-
}
|
|
560
|
-
}`;
|
|
561
|
-
|
|
562
|
-
// src/commands/search.ts
|
|
563
704
|
function searchCommand(getClient2, getFormat2) {
|
|
564
|
-
const cmd = new Command7("search").description(
|
|
565
|
-
"
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
async (query, options) => {
|
|
569
|
-
const client = getClient2();
|
|
570
|
-
const result = await client.graphql(SEARCH_COLLECTIONS_QUERY, {
|
|
571
|
-
query,
|
|
572
|
-
limit: parseIntOption(options.limit, "--limit"),
|
|
573
|
-
chains: options.chains?.split(",")
|
|
574
|
-
});
|
|
575
|
-
console.log(formatOutput(result.collectionsByQuery, getFormat2()));
|
|
576
|
-
}
|
|
577
|
-
);
|
|
578
|
-
cmd.command("nfts").description("Search NFTs by name").argument("<query>", "Search query").option("--collection <slug>", "Filter by collection slug").option("--chains <chains>", "Filter by chains (comma-separated)").option("--limit <limit>", "Number of results", "10").action(
|
|
705
|
+
const cmd = new Command7("search").description("Search across collections, tokens, NFTs, and accounts").argument("<query>", "Search query").option(
|
|
706
|
+
"--types <types>",
|
|
707
|
+
"Filter by type (comma-separated: collection,nft,token,account)"
|
|
708
|
+
).option("--chains <chains>", "Filter by chains (comma-separated)").option("--limit <limit>", "Number of results", "20").action(
|
|
579
709
|
async (query, options) => {
|
|
580
710
|
const client = getClient2();
|
|
581
|
-
const
|
|
711
|
+
const params = {
|
|
582
712
|
query,
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
chain: options.chain
|
|
597
|
-
});
|
|
598
|
-
console.log(formatOutput(result.currenciesByQuery, getFormat2()));
|
|
713
|
+
limit: parseIntOption(options.limit, "--limit")
|
|
714
|
+
};
|
|
715
|
+
if (options.types) {
|
|
716
|
+
params.asset_types = options.types;
|
|
717
|
+
}
|
|
718
|
+
if (options.chains) {
|
|
719
|
+
params.chains = options.chains;
|
|
720
|
+
}
|
|
721
|
+
const result = await client.get(
|
|
722
|
+
"/api/v2/search",
|
|
723
|
+
params
|
|
724
|
+
);
|
|
725
|
+
console.log(formatOutput(result, getFormat2()));
|
|
599
726
|
}
|
|
600
727
|
);
|
|
601
|
-
cmd.command("accounts").description("Search accounts by username or address").argument("<query>", "Search query").option("--limit <limit>", "Number of results", "10").action(async (query, options) => {
|
|
602
|
-
const client = getClient2();
|
|
603
|
-
const result = await client.graphql(SEARCH_ACCOUNTS_QUERY, {
|
|
604
|
-
query,
|
|
605
|
-
limit: parseIntOption(options.limit, "--limit")
|
|
606
|
-
});
|
|
607
|
-
console.log(formatOutput(result.accountsByQuery, getFormat2()));
|
|
608
|
-
});
|
|
609
728
|
return cmd;
|
|
610
729
|
}
|
|
611
730
|
|
|
@@ -709,7 +828,7 @@ var BANNER = `
|
|
|
709
828
|
|_|
|
|
710
829
|
`;
|
|
711
830
|
var program = new Command10();
|
|
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
|
|
831
|
+
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("--verbose", "Log request and response info to stderr");
|
|
713
832
|
function getClient() {
|
|
714
833
|
const opts = program.opts();
|
|
715
834
|
const apiKey = opts.apiKey ?? process.env.OPENSEA_API_KEY;
|
|
@@ -729,7 +848,9 @@ function getClient() {
|
|
|
729
848
|
}
|
|
730
849
|
function getFormat() {
|
|
731
850
|
const opts = program.opts();
|
|
732
|
-
|
|
851
|
+
if (opts.format === "table") return "table";
|
|
852
|
+
if (opts.format === "toon") return "toon";
|
|
853
|
+
return "json";
|
|
733
854
|
}
|
|
734
855
|
program.addCommand(collectionsCommand(getClient, getFormat));
|
|
735
856
|
program.addCommand(nftsCommand(getClient, getFormat));
|