@opensea/cli 0.4.0 → 0.4.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/README.md +2 -1
- package/dist/cli.js +265 -226
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +62 -90
- package/dist/index.js +195 -189
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -269,93 +269,58 @@ interface SwapQuoteResponse {
|
|
|
269
269
|
quote: SwapQuote;
|
|
270
270
|
transactions: SwapTransaction[];
|
|
271
271
|
}
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
description: string;
|
|
276
|
-
imageUrl: string;
|
|
277
|
-
chain: {
|
|
278
|
-
identifier: string;
|
|
279
|
-
name: string;
|
|
280
|
-
};
|
|
281
|
-
stats: {
|
|
282
|
-
totalSupply: number;
|
|
283
|
-
ownerCount: number;
|
|
284
|
-
volume: {
|
|
285
|
-
usd: number;
|
|
286
|
-
};
|
|
287
|
-
sales: number;
|
|
288
|
-
} | null;
|
|
289
|
-
floorPrice: {
|
|
290
|
-
pricePerItem: {
|
|
291
|
-
usd: number;
|
|
292
|
-
native: {
|
|
293
|
-
unit: number;
|
|
294
|
-
symbol: string;
|
|
295
|
-
};
|
|
296
|
-
};
|
|
297
|
-
} | null;
|
|
298
|
-
}
|
|
299
|
-
interface SearchNFTResult {
|
|
300
|
-
tokenId: string;
|
|
272
|
+
type SearchAssetType = "collection" | "nft" | "token" | "account";
|
|
273
|
+
interface SearchResultCollection {
|
|
274
|
+
collection: string;
|
|
301
275
|
name: string;
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
slug: string;
|
|
307
|
-
name: string;
|
|
308
|
-
};
|
|
309
|
-
chain: {
|
|
310
|
-
identifier: string;
|
|
311
|
-
name: string;
|
|
312
|
-
};
|
|
313
|
-
bestListing: {
|
|
314
|
-
pricePerItem: {
|
|
315
|
-
usd: number;
|
|
316
|
-
native: {
|
|
317
|
-
unit: number;
|
|
318
|
-
symbol: string;
|
|
319
|
-
};
|
|
320
|
-
};
|
|
321
|
-
} | null;
|
|
322
|
-
owner: {
|
|
323
|
-
address: string;
|
|
324
|
-
displayName: string;
|
|
325
|
-
} | null;
|
|
276
|
+
image_url: string | null;
|
|
277
|
+
is_disabled: boolean;
|
|
278
|
+
is_nsfw: boolean;
|
|
279
|
+
opensea_url: string;
|
|
326
280
|
}
|
|
327
|
-
interface
|
|
281
|
+
interface SearchResultToken {
|
|
282
|
+
address: string;
|
|
283
|
+
chain: string;
|
|
328
284
|
name: string;
|
|
329
285
|
symbol: string;
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
};
|
|
343
|
-
} | null;
|
|
286
|
+
image_url: string | null;
|
|
287
|
+
usd_price: string;
|
|
288
|
+
decimals: number;
|
|
289
|
+
opensea_url: string;
|
|
290
|
+
}
|
|
291
|
+
interface SearchResultNFT {
|
|
292
|
+
identifier: string;
|
|
293
|
+
collection: string;
|
|
294
|
+
contract: string;
|
|
295
|
+
name: string | null;
|
|
296
|
+
image_url: string | null;
|
|
297
|
+
opensea_url: string;
|
|
344
298
|
}
|
|
345
|
-
interface
|
|
299
|
+
interface SearchResultAccount {
|
|
346
300
|
address: string;
|
|
347
|
-
username: string;
|
|
348
|
-
|
|
349
|
-
|
|
301
|
+
username: string | null;
|
|
302
|
+
profile_image_url: string | null;
|
|
303
|
+
opensea_url: string;
|
|
304
|
+
}
|
|
305
|
+
interface SearchResult {
|
|
306
|
+
type: SearchAssetType;
|
|
307
|
+
collection?: SearchResultCollection;
|
|
308
|
+
token?: SearchResultToken;
|
|
309
|
+
nft?: SearchResultNFT;
|
|
310
|
+
account?: SearchResultAccount;
|
|
311
|
+
}
|
|
312
|
+
interface SearchResponse {
|
|
313
|
+
results: SearchResult[];
|
|
350
314
|
}
|
|
351
315
|
|
|
352
316
|
interface OpenSeaClientConfig {
|
|
353
317
|
apiKey: string;
|
|
354
318
|
baseUrl?: string;
|
|
355
|
-
graphqlUrl?: string;
|
|
356
319
|
chain?: string;
|
|
357
320
|
timeout?: number;
|
|
358
321
|
verbose?: boolean;
|
|
322
|
+
maxRetries?: number;
|
|
323
|
+
retryBaseDelay?: number;
|
|
359
324
|
}
|
|
360
325
|
interface CommandOptions {
|
|
361
326
|
apiKey?: string;
|
|
@@ -363,19 +328,29 @@ interface CommandOptions {
|
|
|
363
328
|
format?: "json" | "table";
|
|
364
329
|
raw?: boolean;
|
|
365
330
|
}
|
|
331
|
+
interface HealthResult {
|
|
332
|
+
status: "ok" | "error";
|
|
333
|
+
key_prefix: string;
|
|
334
|
+
authenticated: boolean;
|
|
335
|
+
rate_limited: boolean;
|
|
336
|
+
message: string;
|
|
337
|
+
}
|
|
366
338
|
|
|
367
339
|
declare class OpenSeaClient {
|
|
368
340
|
private apiKey;
|
|
369
341
|
private baseUrl;
|
|
370
|
-
private graphqlUrl;
|
|
371
342
|
private defaultChain;
|
|
372
343
|
private timeoutMs;
|
|
373
344
|
private verbose;
|
|
345
|
+
private maxRetries;
|
|
346
|
+
private retryBaseDelay;
|
|
374
347
|
constructor(config: OpenSeaClientConfig);
|
|
348
|
+
private get defaultHeaders();
|
|
375
349
|
get<T>(path: string, params?: Record<string, unknown>): Promise<T>;
|
|
376
350
|
post<T>(path: string, body?: Record<string, unknown>, params?: Record<string, unknown>): Promise<T>;
|
|
377
|
-
graphql<T>(query: string, variables?: Record<string, unknown>): Promise<T>;
|
|
378
351
|
getDefaultChain(): string;
|
|
352
|
+
getApiKeyPrefix(): string;
|
|
353
|
+
private fetchWithRetry;
|
|
379
354
|
}
|
|
380
355
|
declare class OpenSeaAPIError extends Error {
|
|
381
356
|
statusCode: number;
|
|
@@ -384,6 +359,8 @@ declare class OpenSeaAPIError extends Error {
|
|
|
384
359
|
constructor(statusCode: number, responseBody: string, path: string);
|
|
385
360
|
}
|
|
386
361
|
|
|
362
|
+
declare function checkHealth(client: OpenSeaClient): Promise<HealthResult>;
|
|
363
|
+
|
|
387
364
|
type OutputFormat = "json" | "table" | "toon";
|
|
388
365
|
declare function formatOutput(data: unknown, format: OutputFormat): string;
|
|
389
366
|
|
|
@@ -398,6 +375,7 @@ declare class OpenSeaCLI {
|
|
|
398
375
|
readonly tokens: TokensAPI;
|
|
399
376
|
readonly search: SearchAPI;
|
|
400
377
|
readonly swaps: SwapsAPI;
|
|
378
|
+
readonly health: HealthAPI;
|
|
401
379
|
constructor(config: OpenSeaClientConfig);
|
|
402
380
|
}
|
|
403
381
|
declare class CollectionsAPI {
|
|
@@ -564,22 +542,11 @@ declare class TokensAPI {
|
|
|
564
542
|
declare class SearchAPI {
|
|
565
543
|
private client;
|
|
566
544
|
constructor(client: OpenSeaClient);
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
limit?: number;
|
|
570
|
-
}): Promise<SearchCollectionResult[]>;
|
|
571
|
-
nfts(query: string, options?: {
|
|
572
|
-
collection?: string;
|
|
545
|
+
query(query: string, options?: {
|
|
546
|
+
assetTypes?: SearchAssetType[];
|
|
573
547
|
chains?: string[];
|
|
574
548
|
limit?: number;
|
|
575
|
-
}): Promise<
|
|
576
|
-
tokens(query: string, options?: {
|
|
577
|
-
chain?: string;
|
|
578
|
-
limit?: number;
|
|
579
|
-
}): Promise<SearchTokenResult[]>;
|
|
580
|
-
accounts(query: string, options?: {
|
|
581
|
-
limit?: number;
|
|
582
|
-
}): Promise<SearchAccountResult[]>;
|
|
549
|
+
}): Promise<SearchResponse>;
|
|
583
550
|
}
|
|
584
551
|
declare class SwapsAPI {
|
|
585
552
|
private client;
|
|
@@ -595,7 +562,12 @@ declare class SwapsAPI {
|
|
|
595
562
|
recipient?: string;
|
|
596
563
|
}): Promise<SwapQuoteResponse>;
|
|
597
564
|
}
|
|
565
|
+
declare class HealthAPI {
|
|
566
|
+
private client;
|
|
567
|
+
constructor(client: OpenSeaClient);
|
|
568
|
+
check(): Promise<HealthResult>;
|
|
569
|
+
}
|
|
598
570
|
|
|
599
571
|
declare function formatToon(data: unknown): string;
|
|
600
572
|
|
|
601
|
-
export { type Account, type AssetEvent, type Chain, type Collection, type CollectionOrderBy, type CollectionStats, type CommandOptions, type Contract, type EventAsset, type EventPayment, type EventType, type Fee, type GetTraitsResponse, type Listing, type NFT, type Offer, OpenSeaAPIError, OpenSeaCLI, OpenSeaClient, type OpenSeaClientConfig, type Order, type OrderSide, type OutputFormat, type PaymentToken, type Price, type SafelistStatus, type
|
|
573
|
+
export { type Account, type AssetEvent, type Chain, type Collection, type CollectionOrderBy, type CollectionStats, type CommandOptions, type Contract, type EventAsset, type EventPayment, type EventType, type Fee, type GetTraitsResponse, type HealthResult, type Listing, type NFT, type Offer, OpenSeaAPIError, OpenSeaCLI, OpenSeaClient, type OpenSeaClientConfig, type Order, type OrderSide, type OutputFormat, type PaymentToken, type Price, type SafelistStatus, type SearchAssetType, type SearchResponse, type SearchResult, type SearchResultAccount, type SearchResultCollection, type SearchResultNFT, type SearchResultToken, type SwapQuote, type SwapQuoteResponse, type SwapTransaction, type Token, type TokenDetails, type TokenSocials, type TokenStats, type Trait, type TraitCategories, type TraitCounts, checkHealth, formatOutput, formatToon };
|
package/dist/index.js
CHANGED
|
@@ -1,21 +1,47 @@
|
|
|
1
1
|
// src/client.ts
|
|
2
2
|
var DEFAULT_BASE_URL = "https://api.opensea.io";
|
|
3
|
-
var DEFAULT_GRAPHQL_URL = "https://gql.opensea.io/graphql";
|
|
4
3
|
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
4
|
+
var USER_AGENT = `opensea-cli/${"0.4.2"}`;
|
|
5
|
+
var DEFAULT_MAX_RETRIES = 0;
|
|
6
|
+
var DEFAULT_RETRY_BASE_DELAY_MS = 1e3;
|
|
7
|
+
function isRetryableStatus(status, method) {
|
|
8
|
+
if (status === 429) return true;
|
|
9
|
+
return status >= 500 && method === "GET";
|
|
10
|
+
}
|
|
11
|
+
function parseRetryAfter(header) {
|
|
12
|
+
if (!header) return void 0;
|
|
13
|
+
const seconds = Number(header);
|
|
14
|
+
if (!Number.isNaN(seconds)) return seconds * 1e3;
|
|
15
|
+
const date = Date.parse(header);
|
|
16
|
+
if (!Number.isNaN(date)) return Math.max(0, date - Date.now());
|
|
17
|
+
return void 0;
|
|
18
|
+
}
|
|
19
|
+
function sleep(ms) {
|
|
20
|
+
return new Promise((resolve) => setTimeout(resolve, ms));
|
|
21
|
+
}
|
|
5
22
|
var OpenSeaClient = class {
|
|
6
23
|
apiKey;
|
|
7
24
|
baseUrl;
|
|
8
|
-
graphqlUrl;
|
|
9
25
|
defaultChain;
|
|
10
26
|
timeoutMs;
|
|
11
27
|
verbose;
|
|
28
|
+
maxRetries;
|
|
29
|
+
retryBaseDelay;
|
|
12
30
|
constructor(config) {
|
|
13
31
|
this.apiKey = config.apiKey;
|
|
14
32
|
this.baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
|
|
15
|
-
this.graphqlUrl = config.graphqlUrl ?? DEFAULT_GRAPHQL_URL;
|
|
16
33
|
this.defaultChain = config.chain ?? "ethereum";
|
|
17
34
|
this.timeoutMs = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
18
35
|
this.verbose = config.verbose ?? false;
|
|
36
|
+
this.maxRetries = config.maxRetries ?? DEFAULT_MAX_RETRIES;
|
|
37
|
+
this.retryBaseDelay = config.retryBaseDelay ?? DEFAULT_RETRY_BASE_DELAY_MS;
|
|
38
|
+
}
|
|
39
|
+
get defaultHeaders() {
|
|
40
|
+
return {
|
|
41
|
+
Accept: "application/json",
|
|
42
|
+
"User-Agent": USER_AGENT,
|
|
43
|
+
"x-api-key": this.apiKey
|
|
44
|
+
};
|
|
19
45
|
}
|
|
20
46
|
async get(path, params) {
|
|
21
47
|
const url = new URL(`${this.baseUrl}${path}`);
|
|
@@ -29,21 +55,14 @@ var OpenSeaClient = class {
|
|
|
29
55
|
if (this.verbose) {
|
|
30
56
|
console.error(`[verbose] GET ${url.toString()}`);
|
|
31
57
|
}
|
|
32
|
-
const response = await
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
58
|
+
const response = await this.fetchWithRetry(
|
|
59
|
+
url.toString(),
|
|
60
|
+
{
|
|
61
|
+
method: "GET",
|
|
62
|
+
headers: this.defaultHeaders
|
|
37
63
|
},
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
if (this.verbose) {
|
|
41
|
-
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
42
|
-
}
|
|
43
|
-
if (!response.ok) {
|
|
44
|
-
const body = await response.text();
|
|
45
|
-
throw new OpenSeaAPIError(response.status, body, path);
|
|
46
|
-
}
|
|
64
|
+
path
|
|
65
|
+
);
|
|
47
66
|
return response.json();
|
|
48
67
|
}
|
|
49
68
|
async post(path, body, params) {
|
|
@@ -55,68 +74,67 @@ var OpenSeaClient = class {
|
|
|
55
74
|
}
|
|
56
75
|
}
|
|
57
76
|
}
|
|
58
|
-
const headers = {
|
|
59
|
-
Accept: "application/json",
|
|
60
|
-
"x-api-key": this.apiKey
|
|
61
|
-
};
|
|
77
|
+
const headers = { ...this.defaultHeaders };
|
|
62
78
|
if (body) {
|
|
63
79
|
headers["Content-Type"] = "application/json";
|
|
64
80
|
}
|
|
65
81
|
if (this.verbose) {
|
|
66
82
|
console.error(`[verbose] POST ${url.toString()}`);
|
|
67
83
|
}
|
|
68
|
-
const response = await
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
if (this.verbose) {
|
|
75
|
-
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
76
|
-
}
|
|
77
|
-
if (!response.ok) {
|
|
78
|
-
const text = await response.text();
|
|
79
|
-
throw new OpenSeaAPIError(response.status, text, path);
|
|
80
|
-
}
|
|
81
|
-
return response.json();
|
|
82
|
-
}
|
|
83
|
-
async graphql(query, variables) {
|
|
84
|
-
if (this.verbose) {
|
|
85
|
-
console.error(`[verbose] POST ${this.graphqlUrl}`);
|
|
86
|
-
}
|
|
87
|
-
const response = await fetch(this.graphqlUrl, {
|
|
88
|
-
method: "POST",
|
|
89
|
-
headers: {
|
|
90
|
-
"Content-Type": "application/json",
|
|
91
|
-
Accept: "application/json",
|
|
92
|
-
"x-api-key": this.apiKey
|
|
84
|
+
const response = await this.fetchWithRetry(
|
|
85
|
+
url.toString(),
|
|
86
|
+
{
|
|
87
|
+
method: "POST",
|
|
88
|
+
headers,
|
|
89
|
+
body: body ? JSON.stringify(body) : void 0
|
|
93
90
|
},
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
if (this.verbose) {
|
|
98
|
-
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
99
|
-
}
|
|
100
|
-
if (!response.ok) {
|
|
101
|
-
const body = await response.text();
|
|
102
|
-
throw new OpenSeaAPIError(response.status, body, "graphql");
|
|
103
|
-
}
|
|
104
|
-
const json = await response.json();
|
|
105
|
-
if (json.errors?.length) {
|
|
106
|
-
throw new OpenSeaAPIError(
|
|
107
|
-
400,
|
|
108
|
-
json.errors.map((e) => e.message).join("; "),
|
|
109
|
-
"graphql"
|
|
110
|
-
);
|
|
111
|
-
}
|
|
112
|
-
if (!json.data) {
|
|
113
|
-
throw new OpenSeaAPIError(500, "GraphQL response missing data", "graphql");
|
|
114
|
-
}
|
|
115
|
-
return json.data;
|
|
91
|
+
path
|
|
92
|
+
);
|
|
93
|
+
return response.json();
|
|
116
94
|
}
|
|
117
95
|
getDefaultChain() {
|
|
118
96
|
return this.defaultChain;
|
|
119
97
|
}
|
|
98
|
+
getApiKeyPrefix() {
|
|
99
|
+
if (this.apiKey.length < 8) return "***";
|
|
100
|
+
return `${this.apiKey.slice(0, 4)}...`;
|
|
101
|
+
}
|
|
102
|
+
async fetchWithRetry(url, init, path) {
|
|
103
|
+
for (let attempt = 0; ; attempt++) {
|
|
104
|
+
const response = await fetch(url, {
|
|
105
|
+
...init,
|
|
106
|
+
signal: AbortSignal.timeout(this.timeoutMs)
|
|
107
|
+
});
|
|
108
|
+
if (this.verbose) {
|
|
109
|
+
console.error(`[verbose] ${response.status} ${response.statusText}`);
|
|
110
|
+
}
|
|
111
|
+
if (response.ok) {
|
|
112
|
+
return response;
|
|
113
|
+
}
|
|
114
|
+
const method = init.method ?? "GET";
|
|
115
|
+
if (attempt < this.maxRetries && isRetryableStatus(response.status, method)) {
|
|
116
|
+
const retryAfterMs = parseRetryAfter(
|
|
117
|
+
response.headers.get("Retry-After")
|
|
118
|
+
);
|
|
119
|
+
const backoffMs = this.retryBaseDelay * 2 ** attempt;
|
|
120
|
+
const jitterMs = Math.random() * this.retryBaseDelay;
|
|
121
|
+
const delayMs = Math.max(retryAfterMs ?? 0, backoffMs) + jitterMs;
|
|
122
|
+
if (this.verbose) {
|
|
123
|
+
console.error(
|
|
124
|
+
`[verbose] Retry ${attempt + 1}/${this.maxRetries} after ${Math.round(delayMs)}ms (status ${response.status})`
|
|
125
|
+
);
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
await response.body?.cancel();
|
|
129
|
+
} catch {
|
|
130
|
+
}
|
|
131
|
+
await sleep(delayMs);
|
|
132
|
+
continue;
|
|
133
|
+
}
|
|
134
|
+
const text = await response.text();
|
|
135
|
+
throw new OpenSeaAPIError(response.status, text, path);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
120
138
|
};
|
|
121
139
|
var OpenSeaAPIError = class extends Error {
|
|
122
140
|
constructor(statusCode, responseBody, path) {
|
|
@@ -128,6 +146,68 @@ var OpenSeaAPIError = class extends Error {
|
|
|
128
146
|
}
|
|
129
147
|
};
|
|
130
148
|
|
|
149
|
+
// src/health.ts
|
|
150
|
+
async function checkHealth(client) {
|
|
151
|
+
const keyPrefix = client.getApiKeyPrefix();
|
|
152
|
+
try {
|
|
153
|
+
await client.get("/api/v2/collections", { limit: 1 });
|
|
154
|
+
} catch (error) {
|
|
155
|
+
let message;
|
|
156
|
+
if (error instanceof OpenSeaAPIError) {
|
|
157
|
+
message = error.statusCode === 429 ? "Rate limited: too many requests" : `API error (${error.statusCode}): ${error.responseBody}`;
|
|
158
|
+
} else {
|
|
159
|
+
message = `Network error: ${error.message}`;
|
|
160
|
+
}
|
|
161
|
+
return {
|
|
162
|
+
status: "error",
|
|
163
|
+
key_prefix: keyPrefix,
|
|
164
|
+
authenticated: false,
|
|
165
|
+
rate_limited: error instanceof OpenSeaAPIError && error.statusCode === 429,
|
|
166
|
+
message
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
try {
|
|
170
|
+
await client.get("/api/v2/listings/collection/boredapeyachtclub/all", {
|
|
171
|
+
limit: 1
|
|
172
|
+
});
|
|
173
|
+
return {
|
|
174
|
+
status: "ok",
|
|
175
|
+
key_prefix: keyPrefix,
|
|
176
|
+
authenticated: true,
|
|
177
|
+
rate_limited: false,
|
|
178
|
+
message: "Connectivity and authentication are working"
|
|
179
|
+
};
|
|
180
|
+
} catch (error) {
|
|
181
|
+
if (error instanceof OpenSeaAPIError) {
|
|
182
|
+
if (error.statusCode === 429) {
|
|
183
|
+
return {
|
|
184
|
+
status: "error",
|
|
185
|
+
key_prefix: keyPrefix,
|
|
186
|
+
authenticated: false,
|
|
187
|
+
rate_limited: true,
|
|
188
|
+
message: "Rate limited: too many requests"
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (error.statusCode === 401 || error.statusCode === 403) {
|
|
192
|
+
return {
|
|
193
|
+
status: "error",
|
|
194
|
+
key_prefix: keyPrefix,
|
|
195
|
+
authenticated: false,
|
|
196
|
+
rate_limited: false,
|
|
197
|
+
message: `Authentication failed (${error.statusCode}): invalid API key`
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return {
|
|
202
|
+
status: "ok",
|
|
203
|
+
key_prefix: keyPrefix,
|
|
204
|
+
authenticated: false,
|
|
205
|
+
rate_limited: false,
|
|
206
|
+
message: "Connectivity is working but authentication could not be verified"
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
131
211
|
// src/toon.ts
|
|
132
212
|
var INDENT = " ";
|
|
133
213
|
var NUMERIC_RE = /^-?\d+(?:\.\d+)?(?:e[+-]?\d+)?$/i;
|
|
@@ -399,14 +479,21 @@ function formatToon(data) {
|
|
|
399
479
|
}
|
|
400
480
|
|
|
401
481
|
// src/output.ts
|
|
482
|
+
var _outputOptions = {};
|
|
402
483
|
function formatOutput(data, format) {
|
|
484
|
+
const processed = _outputOptions.fields ? filterFields(data, _outputOptions.fields) : data;
|
|
485
|
+
let result;
|
|
403
486
|
if (format === "table") {
|
|
404
|
-
|
|
487
|
+
result = formatTable(processed);
|
|
488
|
+
} else if (format === "toon") {
|
|
489
|
+
result = formatToon(processed);
|
|
490
|
+
} else {
|
|
491
|
+
result = JSON.stringify(processed, null, 2);
|
|
405
492
|
}
|
|
406
|
-
if (
|
|
407
|
-
|
|
493
|
+
if (_outputOptions.maxLines != null) {
|
|
494
|
+
result = truncateOutput(result, _outputOptions.maxLines);
|
|
408
495
|
}
|
|
409
|
-
return
|
|
496
|
+
return result;
|
|
410
497
|
}
|
|
411
498
|
function formatTable(data) {
|
|
412
499
|
if (Array.isArray(data)) {
|
|
@@ -442,99 +529,31 @@ function formatTable(data) {
|
|
|
442
529
|
}
|
|
443
530
|
return String(data);
|
|
444
531
|
}
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
slug
|
|
451
|
-
name
|
|
452
|
-
description
|
|
453
|
-
imageUrl
|
|
454
|
-
chain {
|
|
455
|
-
identifier
|
|
456
|
-
name
|
|
457
|
-
}
|
|
458
|
-
stats {
|
|
459
|
-
totalSupply
|
|
460
|
-
ownerCount
|
|
461
|
-
volume {
|
|
462
|
-
usd
|
|
463
|
-
}
|
|
464
|
-
sales
|
|
465
|
-
}
|
|
466
|
-
floorPrice {
|
|
467
|
-
pricePerItem {
|
|
468
|
-
usd
|
|
469
|
-
native {
|
|
470
|
-
unit
|
|
471
|
-
symbol
|
|
472
|
-
}
|
|
473
|
-
}
|
|
474
|
-
}
|
|
475
|
-
}
|
|
476
|
-
}`;
|
|
477
|
-
var SEARCH_NFTS_QUERY = `
|
|
478
|
-
query SearchItems($query: String!, $collectionSlug: String, $limit: Int, $chains: [ChainIdentifier!]) {
|
|
479
|
-
itemsByQuery(query: $query, collectionSlug: $collectionSlug, limit: $limit, chains: $chains) {
|
|
480
|
-
tokenId
|
|
481
|
-
name
|
|
482
|
-
description
|
|
483
|
-
imageUrl
|
|
484
|
-
contractAddress
|
|
485
|
-
collection {
|
|
486
|
-
slug
|
|
487
|
-
name
|
|
488
|
-
}
|
|
489
|
-
chain {
|
|
490
|
-
identifier
|
|
491
|
-
name
|
|
492
|
-
}
|
|
493
|
-
bestListing {
|
|
494
|
-
pricePerItem {
|
|
495
|
-
usd
|
|
496
|
-
native {
|
|
497
|
-
unit
|
|
498
|
-
symbol
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
}
|
|
502
|
-
owner {
|
|
503
|
-
address
|
|
504
|
-
displayName
|
|
532
|
+
function pickFields(obj, fields) {
|
|
533
|
+
const result = {};
|
|
534
|
+
for (const field of fields) {
|
|
535
|
+
if (field in obj) {
|
|
536
|
+
result[field] = obj[field];
|
|
505
537
|
}
|
|
506
538
|
}
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
symbol
|
|
513
|
-
imageUrl
|
|
514
|
-
usdPrice
|
|
515
|
-
contractAddress
|
|
516
|
-
chain {
|
|
517
|
-
identifier
|
|
518
|
-
name
|
|
519
|
-
}
|
|
520
|
-
stats {
|
|
521
|
-
marketCapUsd
|
|
522
|
-
oneDay {
|
|
523
|
-
priceChange
|
|
524
|
-
volume
|
|
525
|
-
}
|
|
526
|
-
}
|
|
539
|
+
return result;
|
|
540
|
+
}
|
|
541
|
+
function filterFields(data, fields) {
|
|
542
|
+
if (Array.isArray(data)) {
|
|
543
|
+
return data.map((item) => filterFields(item, fields));
|
|
527
544
|
}
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
query SearchAccounts($query: String!, $limit: Int) {
|
|
531
|
-
accountsByQuery(query: $query, limit: $limit) {
|
|
532
|
-
address
|
|
533
|
-
username
|
|
534
|
-
imageUrl
|
|
535
|
-
isVerified
|
|
545
|
+
if (data && typeof data === "object") {
|
|
546
|
+
return pickFields(data, fields);
|
|
536
547
|
}
|
|
537
|
-
|
|
548
|
+
return data;
|
|
549
|
+
}
|
|
550
|
+
function truncateOutput(text, maxLines) {
|
|
551
|
+
const lines = text.split("\n");
|
|
552
|
+
if (lines.length <= maxLines) return text;
|
|
553
|
+
const omitted = lines.length - maxLines;
|
|
554
|
+
return lines.slice(0, maxLines).join("\n") + `
|
|
555
|
+
... (${omitted} more line${omitted === 1 ? "" : "s"})`;
|
|
556
|
+
}
|
|
538
557
|
|
|
539
558
|
// src/sdk.ts
|
|
540
559
|
var OpenSeaCLI = class {
|
|
@@ -548,6 +567,7 @@ var OpenSeaCLI = class {
|
|
|
548
567
|
tokens;
|
|
549
568
|
search;
|
|
550
569
|
swaps;
|
|
570
|
+
health;
|
|
551
571
|
constructor(config) {
|
|
552
572
|
this.client = new OpenSeaClient(config);
|
|
553
573
|
this.collections = new CollectionsAPI(this.client);
|
|
@@ -559,6 +579,7 @@ var OpenSeaCLI = class {
|
|
|
559
579
|
this.tokens = new TokensAPI(this.client);
|
|
560
580
|
this.search = new SearchAPI(this.client);
|
|
561
581
|
this.swaps = new SwapsAPI(this.client);
|
|
582
|
+
this.health = new HealthAPI(this.client);
|
|
562
583
|
}
|
|
563
584
|
};
|
|
564
585
|
var CollectionsAPI = class {
|
|
@@ -750,37 +771,13 @@ var SearchAPI = class {
|
|
|
750
771
|
constructor(client) {
|
|
751
772
|
this.client = client;
|
|
752
773
|
}
|
|
753
|
-
async
|
|
754
|
-
|
|
755
|
-
query,
|
|
756
|
-
limit: options?.limit,
|
|
757
|
-
chains: options?.chains
|
|
758
|
-
});
|
|
759
|
-
return result.collectionsByQuery;
|
|
760
|
-
}
|
|
761
|
-
async nfts(query, options) {
|
|
762
|
-
const result = await this.client.graphql(SEARCH_NFTS_QUERY, {
|
|
763
|
-
query,
|
|
764
|
-
collectionSlug: options?.collection,
|
|
765
|
-
limit: options?.limit,
|
|
766
|
-
chains: options?.chains
|
|
767
|
-
});
|
|
768
|
-
return result.itemsByQuery;
|
|
769
|
-
}
|
|
770
|
-
async tokens(query, options) {
|
|
771
|
-
const result = await this.client.graphql(SEARCH_TOKENS_QUERY, {
|
|
772
|
-
query,
|
|
773
|
-
limit: options?.limit,
|
|
774
|
-
chain: options?.chain
|
|
775
|
-
});
|
|
776
|
-
return result.currenciesByQuery;
|
|
777
|
-
}
|
|
778
|
-
async accounts(query, options) {
|
|
779
|
-
const result = await this.client.graphql(SEARCH_ACCOUNTS_QUERY, {
|
|
774
|
+
async query(query, options) {
|
|
775
|
+
return this.client.get("/api/v2/search", {
|
|
780
776
|
query,
|
|
777
|
+
asset_types: options?.assetTypes?.join(","),
|
|
778
|
+
chains: options?.chains?.join(","),
|
|
781
779
|
limit: options?.limit
|
|
782
780
|
});
|
|
783
|
-
return result.accountsByQuery;
|
|
784
781
|
}
|
|
785
782
|
};
|
|
786
783
|
var SwapsAPI = class {
|
|
@@ -800,10 +797,19 @@ var SwapsAPI = class {
|
|
|
800
797
|
});
|
|
801
798
|
}
|
|
802
799
|
};
|
|
800
|
+
var HealthAPI = class {
|
|
801
|
+
constructor(client) {
|
|
802
|
+
this.client = client;
|
|
803
|
+
}
|
|
804
|
+
async check() {
|
|
805
|
+
return checkHealth(this.client);
|
|
806
|
+
}
|
|
807
|
+
};
|
|
803
808
|
export {
|
|
804
809
|
OpenSeaAPIError,
|
|
805
810
|
OpenSeaCLI,
|
|
806
811
|
OpenSeaClient,
|
|
812
|
+
checkHealth,
|
|
807
813
|
formatOutput,
|
|
808
814
|
formatToon
|
|
809
815
|
};
|