cabalspy-id 0.0.0-stage → 0.5.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/CHANGELOG.md +146 -0
- package/LICENSE +21 -0
- package/README.md +504 -2
- package/dist/api.cjs +74 -0
- package/dist/api.cjs.map +1 -0
- package/dist/api.d.cts +193 -0
- package/dist/api.d.ts +193 -0
- package/dist/api.js +74 -0
- package/dist/api.js.map +1 -0
- package/dist/chunk-A2ZAFAWC.cjs +1 -0
- package/dist/chunk-A2ZAFAWC.cjs.map +1 -0
- package/dist/chunk-ABFIPCBY.cjs +109 -0
- package/dist/chunk-ABFIPCBY.cjs.map +1 -0
- package/dist/chunk-CJFIOVBA.js +1 -0
- package/dist/chunk-CJFIOVBA.js.map +1 -0
- package/dist/chunk-DBYCRBVS.js +400 -0
- package/dist/chunk-DBYCRBVS.js.map +1 -0
- package/dist/chunk-PKFIMBPW.cjs +444 -0
- package/dist/chunk-PKFIMBPW.cjs.map +1 -0
- package/dist/chunk-ULEBNY2A.cjs +1301 -0
- package/dist/chunk-ULEBNY2A.cjs.map +1 -0
- package/dist/chunk-VDFCMYLR.cjs +400 -0
- package/dist/chunk-VDFCMYLR.cjs.map +1 -0
- package/dist/chunk-VOTYIQAY.js +109 -0
- package/dist/chunk-VOTYIQAY.js.map +1 -0
- package/dist/chunk-XLBO2RSL.js +1301 -0
- package/dist/chunk-XLBO2RSL.js.map +1 -0
- package/dist/chunk-Z23B5TY6.js +444 -0
- package/dist/chunk-Z23B5TY6.js.map +1 -0
- package/dist/index.cjs +105 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.js +105 -0
- package/dist/index.js.map +1 -0
- package/dist/react.cjs +361 -0
- package/dist/react.cjs.map +1 -0
- package/dist/react.d.cts +315 -0
- package/dist/react.d.ts +315 -0
- package/dist/react.js +333 -0
- package/dist/react.js.map +1 -0
- package/dist/thesis.cjs +76 -0
- package/dist/thesis.cjs.map +1 -0
- package/dist/thesis.d.cts +221 -0
- package/dist/thesis.d.ts +221 -0
- package/dist/thesis.js +76 -0
- package/dist/thesis.js.map +1 -0
- package/dist/types-UZeY9n1e.d.cts +689 -0
- package/dist/types-UZeY9n1e.d.ts +689 -0
- package/dist/users-3DAw88_U.d.cts +767 -0
- package/dist/users-B4r33i4O.d.ts +767 -0
- package/dist/widget.cjs +233 -0
- package/dist/widget.cjs.map +1 -0
- package/dist/widget.d.cts +226 -0
- package/dist/widget.d.ts +226 -0
- package/dist/widget.js +233 -0
- package/dist/widget.js.map +1 -0
- package/package.json +145 -4
|
@@ -0,0 +1,767 @@
|
|
|
1
|
+
import { d as Chain, S as Scope, ab as Trade, I as ThesisLiveItem, Z as ThesisReactionUpdate, a0 as ThesisRemoved, a as ApiResponse, H as HealthResponse, M as MeResponse, v as Profile, ag as WalletLookupResponse, p as Period, a9 as TrackerResponse, f as HistoryResponse, h as HistoryTrade, j as HoldingsResponse, t as PnlCalendarResponse, m as LeaderboardSort, l as LeaderboardResponse, k as LeaderboardEntry, a3 as ThesisSort, a4 as ThesisStance, y as Thesis, a5 as ThesisSummary, F as ThesisEligibility, G as ThesisEmoji, _ as ThesisReactions, a2 as ThesisReportReason, Q as ThesisNotifications, ah as WebhookEvent } from './types-UZeY9n1e.js';
|
|
2
|
+
|
|
3
|
+
interface RateLimitInfo {
|
|
4
|
+
/** Requests per second allowed by the plan. `null` when the header is absent. */
|
|
5
|
+
limit: number | null;
|
|
6
|
+
remaining: number | null;
|
|
7
|
+
/** Seconds until the current one-second window resets. */
|
|
8
|
+
reset: number | null;
|
|
9
|
+
}
|
|
10
|
+
/** Error body of the Data API: `{"success": false, "error": {...}}`. */
|
|
11
|
+
interface ApiErrorBody {
|
|
12
|
+
code: string;
|
|
13
|
+
message: string;
|
|
14
|
+
request_id: string;
|
|
15
|
+
/** Link to the error's documentation, e.g. https://docs.cabalspy.xyz/cabalspy-id/errors#wallet_not_found */
|
|
16
|
+
docs: string;
|
|
17
|
+
parameter?: string;
|
|
18
|
+
allowed?: unknown[];
|
|
19
|
+
/** Set on `plan_user_limit`. */
|
|
20
|
+
limited?: boolean;
|
|
21
|
+
[key: string]: unknown;
|
|
22
|
+
}
|
|
23
|
+
interface CabalSpyIDErrorOptions {
|
|
24
|
+
status?: number;
|
|
25
|
+
code?: string;
|
|
26
|
+
requestId?: string;
|
|
27
|
+
docs?: string;
|
|
28
|
+
parameter?: string;
|
|
29
|
+
allowed?: unknown[];
|
|
30
|
+
rateLimit?: RateLimitInfo;
|
|
31
|
+
body?: unknown;
|
|
32
|
+
}
|
|
33
|
+
/** Base class for every error thrown by this SDK. */
|
|
34
|
+
declare class CabalSpyIDError extends Error {
|
|
35
|
+
readonly status: number;
|
|
36
|
+
readonly code: string;
|
|
37
|
+
readonly requestId?: string;
|
|
38
|
+
readonly docs?: string;
|
|
39
|
+
readonly parameter?: string;
|
|
40
|
+
readonly allowed?: unknown[];
|
|
41
|
+
readonly rateLimit: RateLimitInfo;
|
|
42
|
+
/** The parsed response body, when there was one. */
|
|
43
|
+
readonly body?: unknown;
|
|
44
|
+
constructor(message: string, opts?: CabalSpyIDErrorOptions);
|
|
45
|
+
}
|
|
46
|
+
/** 400 — missing_parameter, invalid_parameter, instance_required */
|
|
47
|
+
declare class BadRequestError extends CabalSpyIDError {
|
|
48
|
+
}
|
|
49
|
+
/** 401 — missing_api_key; thesis API: client_id_required, invalid_client */
|
|
50
|
+
declare class AuthenticationError extends CabalSpyIDError {
|
|
51
|
+
}
|
|
52
|
+
/** 403 — invalid_api_key, product_not_enabled, no_instance, scope_not_allowed; thesis API: origin_not_allowed */
|
|
53
|
+
declare class PermissionError extends CabalSpyIDError {
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* 403 — plan_user_limit. The person signed in beyond the plan's user limit:
|
|
57
|
+
* the platform receives no data for them until it upgrades.
|
|
58
|
+
*/
|
|
59
|
+
declare class PlanUserLimitError extends PermissionError {
|
|
60
|
+
readonly limited: true;
|
|
61
|
+
}
|
|
62
|
+
/** 404 — profile_not_found, wallet_not_found, instance_not_found */
|
|
63
|
+
declare class NotFoundError extends CabalSpyIDError {
|
|
64
|
+
}
|
|
65
|
+
/** 429 — rate_limit_exceeded; thesis API: rate_limited (Retry-After 60) */
|
|
66
|
+
declare class RateLimitError extends CabalSpyIDError {
|
|
67
|
+
/** Seconds until the next request is allowed, taken from Retry-After. */
|
|
68
|
+
readonly retryAfter: number | null;
|
|
69
|
+
constructor(message: string, opts?: CabalSpyIDErrorOptions & {
|
|
70
|
+
retryAfter?: number | null;
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
/** 5xx — internal_error, service_unavailable */
|
|
74
|
+
declare class ServerError extends CabalSpyIDError {
|
|
75
|
+
}
|
|
76
|
+
/** Network failure, timeout or aborted connection. */
|
|
77
|
+
declare class ConnectionError extends CabalSpyIDError {
|
|
78
|
+
}
|
|
79
|
+
/** Response was not valid JSON, or did not have the expected envelope. */
|
|
80
|
+
declare class InvalidResponseError extends CabalSpyIDError {
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* An error from the OpenID Connect endpoints (`/oauth/token`, `/oauth/userinfo`,
|
|
84
|
+
* `/oauth/revoke`) or from the authorization redirect, in OAuth's own format:
|
|
85
|
+
* `code` is the OAuth `error` (invalid_grant, invalid_client, access_denied …).
|
|
86
|
+
*/
|
|
87
|
+
declare class OAuthError extends CabalSpyIDError {
|
|
88
|
+
readonly error: string;
|
|
89
|
+
readonly errorDescription?: string;
|
|
90
|
+
constructor(error: string, description?: string, opts?: CabalSpyIDErrorOptions);
|
|
91
|
+
}
|
|
92
|
+
/** An ID or access token failed verification (signature, iss, aud, exp, nonce …). */
|
|
93
|
+
declare class TokenVerificationError extends CabalSpyIDError {
|
|
94
|
+
}
|
|
95
|
+
/** A webhook failed signature or timestamp verification. */
|
|
96
|
+
declare class WebhookVerificationError extends CabalSpyIDError {
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/** `trades`: your users' trades. `theses`: new theses, replies, reactions and removals (public, all users). */
|
|
100
|
+
type StreamTopic = 'trades' | 'theses';
|
|
101
|
+
interface StreamOptions {
|
|
102
|
+
/** What to receive. Default: ['trades'] */
|
|
103
|
+
events?: StreamTopic[];
|
|
104
|
+
/** Only this chain. Default: every chain. */
|
|
105
|
+
blockchain?: Chain;
|
|
106
|
+
/** Theses of one token only (needs `blockchain`). */
|
|
107
|
+
mint?: string;
|
|
108
|
+
/** `global` (every CabalSpy ID user) is Enterprise only. Default: instance */
|
|
109
|
+
scope?: Scope;
|
|
110
|
+
/** Instance client_id, when your account has several. */
|
|
111
|
+
instance?: string;
|
|
112
|
+
/** Reconnect automatically after a dropped connection. Default: true */
|
|
113
|
+
reconnect?: boolean;
|
|
114
|
+
/** Initial reconnect delay in ms, doubling up to maxReconnectDelay. Default: 1000 */
|
|
115
|
+
reconnectDelay?: number;
|
|
116
|
+
/** Default: 30_000 */
|
|
117
|
+
maxReconnectDelay?: number;
|
|
118
|
+
/**
|
|
119
|
+
* The server sends a heartbeat every 30 s. When nothing at all arrives for
|
|
120
|
+
* this many ms, the connection is treated as dead and reopened.
|
|
121
|
+
* 0 disables the check. Default: 75_000
|
|
122
|
+
*/
|
|
123
|
+
heartbeatTimeout?: number;
|
|
124
|
+
/**
|
|
125
|
+
* WebSocket implementation. Browsers, Deno, Bun and Node 22+ have a global
|
|
126
|
+
* WebSocket. On Node 18-21, `npm i ws` and pass `{ WebSocketImpl: WebSocket }`.
|
|
127
|
+
*/
|
|
128
|
+
WebSocketImpl?: unknown;
|
|
129
|
+
}
|
|
130
|
+
interface SubscribedEvent {
|
|
131
|
+
blockchain: Chain | 'all';
|
|
132
|
+
scope: Scope;
|
|
133
|
+
events?: StreamTopic[];
|
|
134
|
+
mint?: string | null;
|
|
135
|
+
}
|
|
136
|
+
interface HeartbeatEvent {
|
|
137
|
+
ts: number;
|
|
138
|
+
}
|
|
139
|
+
interface CloseEvent {
|
|
140
|
+
code?: number;
|
|
141
|
+
reason?: string;
|
|
142
|
+
}
|
|
143
|
+
interface ReconnectEvent {
|
|
144
|
+
attempt: number;
|
|
145
|
+
delay: number;
|
|
146
|
+
}
|
|
147
|
+
interface StreamEventMap {
|
|
148
|
+
trade: Trade;
|
|
149
|
+
/** A new thesis (events: theses). */
|
|
150
|
+
thesis: ThesisLiveItem;
|
|
151
|
+
/** A new reply to a thesis. */
|
|
152
|
+
'thesis.reply': ThesisLiveItem;
|
|
153
|
+
/** Reaction counts of a thesis or reply changed. */
|
|
154
|
+
'thesis.reaction': ThesisReactionUpdate;
|
|
155
|
+
/** A thesis or reply was deleted or hidden. */
|
|
156
|
+
'thesis.removed': ThesisRemoved;
|
|
157
|
+
subscribed: SubscribedEvent;
|
|
158
|
+
heartbeat: HeartbeatEvent;
|
|
159
|
+
pong: Record<string, never>;
|
|
160
|
+
open: undefined;
|
|
161
|
+
close: CloseEvent;
|
|
162
|
+
reconnecting: ReconnectEvent;
|
|
163
|
+
error: CabalSpyIDError;
|
|
164
|
+
/** Every parsed message, before dispatch. */
|
|
165
|
+
message: Record<string, unknown>;
|
|
166
|
+
}
|
|
167
|
+
type StreamEvent = keyof StreamEventMap;
|
|
168
|
+
type Handler$1<T> = (payload: T) => void;
|
|
169
|
+
/**
|
|
170
|
+
* WebSocket client for the live trade stream.
|
|
171
|
+
*
|
|
172
|
+
* const stream = csid.stream({ blockchain: 'solana' });
|
|
173
|
+
* stream.on('trade', (t) => console.log(t.trader?.username, t.transaction_type, t.value_usd));
|
|
174
|
+
* await stream.connect(); // resolves once the server confirmed the subscription
|
|
175
|
+
*
|
|
176
|
+
* or as an async iterator:
|
|
177
|
+
*
|
|
178
|
+
* for await (const trade of csid.stream()) { … }
|
|
179
|
+
*
|
|
180
|
+
* Reconnects with exponential backoff after a dropped connection or a missed
|
|
181
|
+
* heartbeat. Configuration errors from the server (invalid key, plan without
|
|
182
|
+
* the stream, …) are fatal: they are emitted as 'error' and stop reconnecting.
|
|
183
|
+
*/
|
|
184
|
+
declare class CabalSpyIDStream {
|
|
185
|
+
private readonly url;
|
|
186
|
+
private readonly apiKey;
|
|
187
|
+
private readonly options;
|
|
188
|
+
private ws;
|
|
189
|
+
private readonly opts;
|
|
190
|
+
private readonly handlers;
|
|
191
|
+
private reconnectAttempt;
|
|
192
|
+
private reconnectTimer;
|
|
193
|
+
private watchdog;
|
|
194
|
+
private closedByUser;
|
|
195
|
+
private fatal;
|
|
196
|
+
constructor(url: string, apiKey: string, options?: StreamOptions);
|
|
197
|
+
/** True while the socket is open. */
|
|
198
|
+
get connected(): boolean;
|
|
199
|
+
/** The stream URL including query parameters, with the key masked. */
|
|
200
|
+
get safeUrl(): string;
|
|
201
|
+
private buildUrl;
|
|
202
|
+
on<E extends StreamEvent>(event: E, handler: Handler$1<StreamEventMap[E]>): this;
|
|
203
|
+
off<E extends StreamEvent>(event: E, handler: Handler$1<StreamEventMap[E]>): this;
|
|
204
|
+
private emit;
|
|
205
|
+
/** Opens the socket. Resolves once the server sent `subscribed`. */
|
|
206
|
+
connect(): Promise<SubscribedEvent>;
|
|
207
|
+
private scheduleReconnect;
|
|
208
|
+
private armWatchdog;
|
|
209
|
+
private clearWatchdog;
|
|
210
|
+
/**
|
|
211
|
+
* Sends a ping; the server answers with 'pong'. Not needed to keep the
|
|
212
|
+
* connection alive (the server sends heartbeats), and pinging more often
|
|
213
|
+
* than every 30 s suppresses those heartbeats.
|
|
214
|
+
*/
|
|
215
|
+
ping(): void;
|
|
216
|
+
/** Closes the connection and stops reconnecting. */
|
|
217
|
+
close(): void;
|
|
218
|
+
/**
|
|
219
|
+
* Iterates over trades. Connects if needed; ends when close() is called or
|
|
220
|
+
* a fatal error occurs (which is thrown). Breaking out of the loop closes a
|
|
221
|
+
* connection the iterator opened.
|
|
222
|
+
*/
|
|
223
|
+
[Symbol.asyncIterator](): AsyncGenerator<Trade, void, void>;
|
|
224
|
+
/**
|
|
225
|
+
* Iterates over thesis events (`thesis`, `thesis.reply`, `thesis.reaction`,
|
|
226
|
+
* `thesis.removed`). Open the stream with `events: ['theses']`.
|
|
227
|
+
*
|
|
228
|
+
* for await (const { event, data } of csid.stream({ events: ['theses'] }).theses()) { … }
|
|
229
|
+
*/
|
|
230
|
+
theses(): AsyncGenerator<ThesisStreamEvent, void, void>;
|
|
231
|
+
private iterate;
|
|
232
|
+
}
|
|
233
|
+
/** One thesis event from `stream.theses()`. */
|
|
234
|
+
type ThesisStreamEvent = {
|
|
235
|
+
event: 'thesis';
|
|
236
|
+
data: ThesisLiveItem;
|
|
237
|
+
} | {
|
|
238
|
+
event: 'thesis.reply';
|
|
239
|
+
data: ThesisLiveItem;
|
|
240
|
+
} | {
|
|
241
|
+
event: 'thesis.reaction';
|
|
242
|
+
data: ThesisReactionUpdate;
|
|
243
|
+
} | {
|
|
244
|
+
event: 'thesis.removed';
|
|
245
|
+
data: ThesisRemoved;
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
/** Tokens per connection. */
|
|
249
|
+
declare const MAX_THESES_STREAM_TOKENS = 200;
|
|
250
|
+
interface ThesisTokenRef {
|
|
251
|
+
blockchain: Chain;
|
|
252
|
+
mint: string;
|
|
253
|
+
}
|
|
254
|
+
interface ThesesStreamOptions {
|
|
255
|
+
/** `global` (default): theses from every platform. `instance`: only the ones written on your instance. */
|
|
256
|
+
scope?: 'global' | 'instance';
|
|
257
|
+
/** Instance client_id, when your account has several. */
|
|
258
|
+
instance?: string;
|
|
259
|
+
/** Default: true */
|
|
260
|
+
reconnect?: boolean;
|
|
261
|
+
/** Default: 1000 */
|
|
262
|
+
reconnectDelay?: number;
|
|
263
|
+
/** Default: 30_000 */
|
|
264
|
+
maxReconnectDelay?: number;
|
|
265
|
+
/** The server sends a heartbeat every 30 s; silence this long reopens the socket. 0 disables. Default: 75_000 */
|
|
266
|
+
heartbeatTimeout?: number;
|
|
267
|
+
/** WebSocket implementation for Node < 22 (the `ws` package). */
|
|
268
|
+
WebSocketImpl?: unknown;
|
|
269
|
+
}
|
|
270
|
+
interface ThesesReadyEvent {
|
|
271
|
+
scope: 'global' | 'instance';
|
|
272
|
+
max_tokens: number;
|
|
273
|
+
}
|
|
274
|
+
interface ThesesSubscribedEvent {
|
|
275
|
+
all: boolean;
|
|
276
|
+
tokens: ThesisTokenRef[];
|
|
277
|
+
}
|
|
278
|
+
interface ThesesStreamEventMap {
|
|
279
|
+
ready: ThesesReadyEvent;
|
|
280
|
+
subscribed: ThesesSubscribedEvent;
|
|
281
|
+
thesis: ThesisLiveItem;
|
|
282
|
+
'thesis.reply': ThesisLiveItem;
|
|
283
|
+
'thesis.reaction': ThesisReactionUpdate;
|
|
284
|
+
'thesis.removed': ThesisRemoved;
|
|
285
|
+
heartbeat: {
|
|
286
|
+
ts: number;
|
|
287
|
+
};
|
|
288
|
+
pong: Record<string, never>;
|
|
289
|
+
open: undefined;
|
|
290
|
+
close: {
|
|
291
|
+
code?: number;
|
|
292
|
+
reason?: string;
|
|
293
|
+
};
|
|
294
|
+
reconnecting: {
|
|
295
|
+
attempt: number;
|
|
296
|
+
delay: number;
|
|
297
|
+
};
|
|
298
|
+
error: CabalSpyIDError;
|
|
299
|
+
}
|
|
300
|
+
type Handler<T> = (payload: T) => void;
|
|
301
|
+
/**
|
|
302
|
+
* Live theses for the tokens you choose. Subscriptions are remembered and sent
|
|
303
|
+
* again after every reconnect.
|
|
304
|
+
*
|
|
305
|
+
* const ts = csid.thesesStream();
|
|
306
|
+
* ts.on('thesis', (t) => addMarker(t.blockchain, t.mint, t));
|
|
307
|
+
* await ts.connect();
|
|
308
|
+
* ts.subscribe([{ blockchain: 'solana', mint: MINT_A }, { blockchain: 'base', mint: TOKEN_B }]);
|
|
309
|
+
*
|
|
310
|
+
* for await (const { event, data } of ts) { … }
|
|
311
|
+
*/
|
|
312
|
+
declare class ThesesStream {
|
|
313
|
+
private readonly url;
|
|
314
|
+
private readonly apiKey;
|
|
315
|
+
private readonly options;
|
|
316
|
+
private ws;
|
|
317
|
+
private readonly handlers;
|
|
318
|
+
private readonly tokens;
|
|
319
|
+
private all;
|
|
320
|
+
private attempt;
|
|
321
|
+
private closedByUser;
|
|
322
|
+
private fatal;
|
|
323
|
+
private ready;
|
|
324
|
+
private reconnectTimer;
|
|
325
|
+
private watchdog;
|
|
326
|
+
private readonly opts;
|
|
327
|
+
constructor(url: string, apiKey: string, options?: ThesesStreamOptions);
|
|
328
|
+
private buildUrl;
|
|
329
|
+
/** The URL with the key masked, safe to log. */
|
|
330
|
+
get safeUrl(): string;
|
|
331
|
+
get connected(): boolean;
|
|
332
|
+
/** The tokens currently subscribed (kept across reconnects). */
|
|
333
|
+
get subscriptions(): {
|
|
334
|
+
all: boolean;
|
|
335
|
+
tokens: ThesisTokenRef[];
|
|
336
|
+
};
|
|
337
|
+
on<E extends keyof ThesesStreamEventMap>(event: E, handler: Handler<ThesesStreamEventMap[E]>): this;
|
|
338
|
+
off<E extends keyof ThesesStreamEventMap>(event: E, handler: Handler<ThesesStreamEventMap[E]>): this;
|
|
339
|
+
private emit;
|
|
340
|
+
private send;
|
|
341
|
+
/** Adds tokens (at most 200 per connection). Sent now if connected, and after every reconnect. */
|
|
342
|
+
subscribe(tokens: ThesisTokenRef[]): this;
|
|
343
|
+
/** Removes tokens. */
|
|
344
|
+
unsubscribe(tokens: ThesisTokenRef[]): this;
|
|
345
|
+
/** Every token (all theses). */
|
|
346
|
+
subscribeAll(): this;
|
|
347
|
+
/** Drops every subscription, including subscribeAll(). */
|
|
348
|
+
unsubscribeAll(): this;
|
|
349
|
+
private resubscribe;
|
|
350
|
+
/** Opens the socket; resolves on `ready` (after sending the remembered subscriptions). */
|
|
351
|
+
connect(): Promise<ThesesReadyEvent>;
|
|
352
|
+
private scheduleReconnect;
|
|
353
|
+
private arm;
|
|
354
|
+
private disarm;
|
|
355
|
+
/** Sends a ping (answered with `pong`). Pinging more often than every 30 s suppresses heartbeats. */
|
|
356
|
+
ping(): void;
|
|
357
|
+
/** Closes the socket and stops reconnecting. Subscriptions are kept for a later connect(). */
|
|
358
|
+
close(): void;
|
|
359
|
+
/**
|
|
360
|
+
* Iterates over thesis events as `{ event, data }`. Connects if needed;
|
|
361
|
+
* breaking out closes a connection the iterator opened.
|
|
362
|
+
*/
|
|
363
|
+
[Symbol.asyncIterator](): AsyncGenerator<ThesisStreamEvent, void, void>;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
/**
|
|
367
|
+
* CabalSpy ID Data API client — https://api-id.cabalspy.xyz/v1
|
|
368
|
+
*
|
|
369
|
+
* Auth: Authorization: Bearer <API_KEY>. The same key as the CabalSpy API, with
|
|
370
|
+
* the "CabalSpy ID" toggle enabled on the API keys page of
|
|
371
|
+
* https://apidashboard.cabalspy.xyz.
|
|
372
|
+
*/
|
|
373
|
+
|
|
374
|
+
declare const DEFAULT_BASE_URL = "https://api-id.cabalspy.xyz/v1";
|
|
375
|
+
declare const DEFAULT_STREAM_URL = "wss://api-id.cabalspy.xyz/v1/stream";
|
|
376
|
+
declare const DEFAULT_THESES_STREAM_URL = "wss://api-id.cabalspy.xyz/v1/theses/stream";
|
|
377
|
+
interface CabalSpyIDOptions {
|
|
378
|
+
/**
|
|
379
|
+
* API key. Falls back to CABALSPY_ID_API_KEY, then CABALSPY_API_KEY.
|
|
380
|
+
* Only `health()` works without one.
|
|
381
|
+
*/
|
|
382
|
+
apiKey?: string;
|
|
383
|
+
/**
|
|
384
|
+
* Your instance's client_id (`csid_…`). Only needed when your account has
|
|
385
|
+
* several CabalSpy ID instances. Falls back to CABALSPY_ID_INSTANCE.
|
|
386
|
+
*/
|
|
387
|
+
instance?: string;
|
|
388
|
+
/** REST base URL including /v1. Falls back to CABALSPY_ID_BASE_URL, then the default. */
|
|
389
|
+
baseUrl?: string;
|
|
390
|
+
/** Stream URL. Falls back to CABALSPY_ID_STREAM_URL, then the default. */
|
|
391
|
+
streamUrl?: string;
|
|
392
|
+
/** Theses stream URL. Default: wss://api-id.cabalspy.xyz/v1/theses/stream */
|
|
393
|
+
thesesStreamUrl?: string;
|
|
394
|
+
/** Per-request timeout in milliseconds. Default: 30_000 */
|
|
395
|
+
timeout?: number;
|
|
396
|
+
/** Retries on 429, 5xx and network errors. Default: 2 */
|
|
397
|
+
maxRetries?: number;
|
|
398
|
+
/** Extra headers added to every request. */
|
|
399
|
+
headers?: Record<string, string>;
|
|
400
|
+
/** Custom fetch implementation, for tests or proxies. */
|
|
401
|
+
fetch?: typeof globalThis.fetch;
|
|
402
|
+
}
|
|
403
|
+
/** Response body plus the metadata carried in HTTP headers. */
|
|
404
|
+
interface Envelope<T> extends ApiResponse<T> {
|
|
405
|
+
rateLimit: RateLimitInfo;
|
|
406
|
+
status: number;
|
|
407
|
+
}
|
|
408
|
+
type QueryValue = string | number | boolean | undefined | null;
|
|
409
|
+
type Query = Record<string, QueryValue>;
|
|
410
|
+
interface ScopedParams {
|
|
411
|
+
/** `global` (every CabalSpy ID user) is Enterprise only. Default: instance */
|
|
412
|
+
scope?: Scope;
|
|
413
|
+
}
|
|
414
|
+
interface UsersParams extends ScopedParams {
|
|
415
|
+
/** 1-100. Default: 50 */
|
|
416
|
+
limit?: number;
|
|
417
|
+
/** Only users with the KOL badge. */
|
|
418
|
+
kol?: boolean;
|
|
419
|
+
cursor?: string;
|
|
420
|
+
}
|
|
421
|
+
/** Exactly one of username, csid_id or address. */
|
|
422
|
+
type ProfileParams = ScopedParams & ({
|
|
423
|
+
username: string;
|
|
424
|
+
csid_id?: never;
|
|
425
|
+
address?: never;
|
|
426
|
+
} | {
|
|
427
|
+
csid_id: string;
|
|
428
|
+
username?: never;
|
|
429
|
+
address?: never;
|
|
430
|
+
} | {
|
|
431
|
+
address: string;
|
|
432
|
+
username?: never;
|
|
433
|
+
csid_id?: never;
|
|
434
|
+
});
|
|
435
|
+
interface WalletParams extends ScopedParams {
|
|
436
|
+
blockchain: Chain;
|
|
437
|
+
address: string;
|
|
438
|
+
}
|
|
439
|
+
interface TrackerParams extends WalletParams {
|
|
440
|
+
/** Default: 1d */
|
|
441
|
+
period?: Period;
|
|
442
|
+
}
|
|
443
|
+
interface HistoryParams extends WalletParams {
|
|
444
|
+
/** 1-1000. Default: 500 */
|
|
445
|
+
limit?: number;
|
|
446
|
+
cursor?: string;
|
|
447
|
+
}
|
|
448
|
+
interface LeaderboardParams extends ScopedParams {
|
|
449
|
+
blockchain: Chain;
|
|
450
|
+
/** Default: 1d */
|
|
451
|
+
period?: Period;
|
|
452
|
+
/** Default: volume */
|
|
453
|
+
sort?: LeaderboardSort;
|
|
454
|
+
/** 1-500. Default: 100 */
|
|
455
|
+
limit?: number;
|
|
456
|
+
/** The `next_cursor` of the previous page (a wallet address). */
|
|
457
|
+
cursor?: string;
|
|
458
|
+
}
|
|
459
|
+
interface LatestTransactionsParams extends ScopedParams {
|
|
460
|
+
/** Omit for every chain. */
|
|
461
|
+
blockchain?: Chain;
|
|
462
|
+
/** 1-100. Default: 50 */
|
|
463
|
+
limit?: number;
|
|
464
|
+
}
|
|
465
|
+
interface ThesisTokenParams {
|
|
466
|
+
blockchain: Chain;
|
|
467
|
+
/** Token mint / contract address. */
|
|
468
|
+
mint: string;
|
|
469
|
+
}
|
|
470
|
+
/**
|
|
471
|
+
* `global` (default): theses written on every platform. `instance`: only the
|
|
472
|
+
* ones written on your instance (your apps). Same for every plan.
|
|
473
|
+
*/
|
|
474
|
+
interface ThesisScopeParam {
|
|
475
|
+
scope?: Scope;
|
|
476
|
+
}
|
|
477
|
+
interface ListThesesParams extends ThesisTokenParams, ThesisScopeParam {
|
|
478
|
+
/** Default: new */
|
|
479
|
+
sort?: ThesisSort;
|
|
480
|
+
stance?: ThesisStance;
|
|
481
|
+
/** 1-50. Default: 20 */
|
|
482
|
+
limit?: number;
|
|
483
|
+
cursor?: string;
|
|
484
|
+
/** Viewer: fills `my_reactions` and `is_mine` for this user. */
|
|
485
|
+
csid_id?: string;
|
|
486
|
+
}
|
|
487
|
+
interface ThesisRepliesParams {
|
|
488
|
+
/** The thesis id. */
|
|
489
|
+
id: string;
|
|
490
|
+
/** 1-100. Default: 50 */
|
|
491
|
+
limit?: number;
|
|
492
|
+
cursor?: string;
|
|
493
|
+
csid_id?: string;
|
|
494
|
+
}
|
|
495
|
+
interface LatestThesesParams extends ThesisScopeParam {
|
|
496
|
+
/** Omit for every chain. */
|
|
497
|
+
blockchain?: Chain;
|
|
498
|
+
/** `instance`: only theses of your instance's users. Default: all */
|
|
499
|
+
users?: 'all' | 'instance';
|
|
500
|
+
/** 1-50. Default: 20 */
|
|
501
|
+
limit?: number;
|
|
502
|
+
cursor?: string;
|
|
503
|
+
csid_id?: string;
|
|
504
|
+
}
|
|
505
|
+
/** Exactly one of csid_id or username. */
|
|
506
|
+
type UserThesesParams = {
|
|
507
|
+
limit?: number;
|
|
508
|
+
cursor?: string;
|
|
509
|
+
} & ({
|
|
510
|
+
csid_id: string;
|
|
511
|
+
username?: never;
|
|
512
|
+
} | {
|
|
513
|
+
username: string;
|
|
514
|
+
csid_id?: never;
|
|
515
|
+
});
|
|
516
|
+
/**
|
|
517
|
+
* Writes happen in the name of one of your users: `csid_id` is the `sub` of
|
|
518
|
+
* their ID token. They must have signed in to your app with the scope
|
|
519
|
+
* `thesis` and be within your plan's user limit.
|
|
520
|
+
*/
|
|
521
|
+
interface ThesisWriter {
|
|
522
|
+
csid_id: string;
|
|
523
|
+
}
|
|
524
|
+
interface PostThesisParams extends ThesisTokenParams, ThesisWriter {
|
|
525
|
+
/** Up to 1000 characters. Only holders of the token can post. */
|
|
526
|
+
body: string;
|
|
527
|
+
stance?: ThesisStance;
|
|
528
|
+
}
|
|
529
|
+
interface ReplyToThesisParams extends ThesisWriter {
|
|
530
|
+
thesis_id: string;
|
|
531
|
+
body: string;
|
|
532
|
+
}
|
|
533
|
+
interface ReactToThesisParams extends ThesisWriter {
|
|
534
|
+
thesis_id: string;
|
|
535
|
+
emoji: ThesisEmoji;
|
|
536
|
+
/** false removes the reaction. Default: true */
|
|
537
|
+
on?: boolean;
|
|
538
|
+
}
|
|
539
|
+
interface ReportThesisParams extends ThesisWriter {
|
|
540
|
+
thesis_id: string;
|
|
541
|
+
reason: ThesisReportReason;
|
|
542
|
+
note?: string;
|
|
543
|
+
}
|
|
544
|
+
interface DeleteThesisParams extends ThesisWriter {
|
|
545
|
+
thesis_id: string;
|
|
546
|
+
}
|
|
547
|
+
/**
|
|
548
|
+
* Data API client.
|
|
549
|
+
*
|
|
550
|
+
* const csid = new CabalSpyID({ apiKey: process.env.CABALSPY_API_KEY });
|
|
551
|
+
* const me = await csid.me();
|
|
552
|
+
* const user = await csid.profile({ csid_id: idToken.sub });
|
|
553
|
+
*/
|
|
554
|
+
declare class CabalSpyID {
|
|
555
|
+
readonly baseUrl: string;
|
|
556
|
+
readonly streamUrl: string;
|
|
557
|
+
readonly thesesStreamUrl: string;
|
|
558
|
+
readonly timeout: number;
|
|
559
|
+
readonly maxRetries: number;
|
|
560
|
+
readonly instance?: string;
|
|
561
|
+
private readonly apiKey;
|
|
562
|
+
private readonly extraHeaders;
|
|
563
|
+
private readonly fetchImpl;
|
|
564
|
+
/** Rate limit state from the most recent request. */
|
|
565
|
+
lastRateLimit: RateLimitInfo;
|
|
566
|
+
constructor(options?: CabalSpyIDOptions);
|
|
567
|
+
private authedQuery;
|
|
568
|
+
/** GET returning the full envelope: data, pagination, meta and rate limit. */
|
|
569
|
+
getRaw<T>(path: string, query?: Query, opts?: {
|
|
570
|
+
auth?: boolean;
|
|
571
|
+
}): Promise<Envelope<T>>;
|
|
572
|
+
/** GET returning only the data payload. */
|
|
573
|
+
get<T>(path: string, query?: Query): Promise<T>;
|
|
574
|
+
/**
|
|
575
|
+
* POST with a JSON body, returning the full envelope. POSTs are not retried
|
|
576
|
+
* after a server or network error (the write may have happened); only the
|
|
577
|
+
* API's own rate limit (429 rate_limit_exceeded) is retried.
|
|
578
|
+
*/
|
|
579
|
+
postRaw<T>(path: string, body: Record<string, unknown>): Promise<Envelope<T>>;
|
|
580
|
+
/** POST returning only the data payload. */
|
|
581
|
+
post<T>(path: string, body: Record<string, unknown>): Promise<T>;
|
|
582
|
+
private request;
|
|
583
|
+
/**
|
|
584
|
+
* Walks a cursor-paginated route and yields whole pages.
|
|
585
|
+
*
|
|
586
|
+
* for await (const page of csid.pages((cursor) => csid.usersRaw({ cursor }))) …
|
|
587
|
+
*
|
|
588
|
+
* Reads `pagination` from the envelope or, for the leaderboard, from `data`.
|
|
589
|
+
*/
|
|
590
|
+
pages<T>(fetchPage: (cursor: string | undefined) => Promise<Envelope<T>>, opts?: {
|
|
591
|
+
cursor?: string;
|
|
592
|
+
maxPages?: number;
|
|
593
|
+
}): AsyncGenerator<Envelope<T>, void, void>;
|
|
594
|
+
/** GET /v1/health — service health and trade sync freshness. No API key required. */
|
|
595
|
+
health(): Promise<HealthResponse>;
|
|
596
|
+
/** GET /v1/me — the key's instance, plan, request rate and number of users with data. */
|
|
597
|
+
me(): Promise<MeResponse>;
|
|
598
|
+
/** GET /v1/users — users of your instance (within the plan's user limit), newest first. */
|
|
599
|
+
users(params?: UsersParams): Promise<Profile[]>;
|
|
600
|
+
usersRaw(params?: UsersParams): Promise<Envelope<Profile[]>>;
|
|
601
|
+
/** Iterates over every user, following `next_cursor`. */
|
|
602
|
+
iterUsers(params?: Omit<UsersParams, 'cursor'> & {
|
|
603
|
+
cursor?: string;
|
|
604
|
+
}): AsyncGenerator<Profile, void, void>;
|
|
605
|
+
/**
|
|
606
|
+
* GET /v1/profile — one user by X username, by `csid_id` (the `sub` of their
|
|
607
|
+
* ID token) or by a verified wallet address. Pass exactly one.
|
|
608
|
+
*
|
|
609
|
+
* An anonymous `anon_…` sub throws PlanUserLimitError.
|
|
610
|
+
*/
|
|
611
|
+
profile(params: ProfileParams): Promise<Profile>;
|
|
612
|
+
/** GET /v1/wallets/lookup — which of your users verified this wallet (by an on-chain payment). */
|
|
613
|
+
walletLookup(address: string, params?: ScopedParams): Promise<WalletLookupResponse>;
|
|
614
|
+
/**
|
|
615
|
+
* GET /v1/wallets/tracker — stats, realized PnL, win-rate distribution,
|
|
616
|
+
* tokens, PnL chart (cumulative from 0) and trades of a verified wallet for a
|
|
617
|
+
* period. Same numbers as the CabalSpy API.
|
|
618
|
+
*/
|
|
619
|
+
tracker(params: TrackerParams): Promise<TrackerResponse>;
|
|
620
|
+
/** GET /v1/wallets/history — lifetime stats, token overview and one page of trades. */
|
|
621
|
+
history(params: HistoryParams): Promise<HistoryResponse>;
|
|
622
|
+
historyRaw(params: HistoryParams): Promise<Envelope<HistoryResponse>>;
|
|
623
|
+
/** Iterates over every trade of a wallet, newest first, following `next_cursor`. */
|
|
624
|
+
iterHistory(params: HistoryParams): AsyncGenerator<HistoryTrade, void, void>;
|
|
625
|
+
/** GET /v1/wallets/holdings — current token balances with USD value (dust under $0.01 hidden). */
|
|
626
|
+
holdings(params: WalletParams): Promise<HoldingsResponse>;
|
|
627
|
+
/** GET /v1/wallets/pnl_calendar — realized PnL per UTC day, grouped by month. */
|
|
628
|
+
pnlCalendar(params: WalletParams): Promise<PnlCalendarResponse>;
|
|
629
|
+
/** GET /v1/wallets/leaderboard — your users ranked by volume, PnL, win rate or trades. */
|
|
630
|
+
leaderboard(params: LeaderboardParams): Promise<LeaderboardResponse>;
|
|
631
|
+
leaderboardRaw(params: LeaderboardParams): Promise<Envelope<LeaderboardResponse>>;
|
|
632
|
+
/** Iterates over every leaderboard entry, following `next_cursor`. */
|
|
633
|
+
iterLeaderboard(params: LeaderboardParams): AsyncGenerator<LeaderboardEntry, void, void>;
|
|
634
|
+
/** GET /v1/transactions/latest — the newest trades of your users, each with the trader. */
|
|
635
|
+
latestTransactions(params?: LatestTransactionsParams): Promise<Trade[]>;
|
|
636
|
+
/** GET /v1/theses — theses on a token, newest or top first. */
|
|
637
|
+
listTheses(params: ListThesesParams): Promise<Thesis[]>;
|
|
638
|
+
listThesesRaw(params: ListThesesParams): Promise<Envelope<Thesis[]>>;
|
|
639
|
+
/** Iterates over every thesis on a token, following `next_cursor`. */
|
|
640
|
+
iterTheses(params: ListThesesParams): AsyncGenerator<Thesis, void, void>;
|
|
641
|
+
/** GET /v1/theses/summary — counts (theses, bull, bear, authors) and token info. */
|
|
642
|
+
thesisSummary(params: ThesisTokenParams & ThesisScopeParam): Promise<ThesisSummary>;
|
|
643
|
+
/** GET /v1/theses/item — one thesis or reply. */
|
|
644
|
+
thesis(id: string, params?: {
|
|
645
|
+
csid_id?: string;
|
|
646
|
+
}): Promise<Thesis>;
|
|
647
|
+
/** GET /v1/theses/replies — replies to a thesis. */
|
|
648
|
+
thesisReplies(params: ThesisRepliesParams): Promise<Thesis[]>;
|
|
649
|
+
thesisRepliesRaw(params: ThesisRepliesParams): Promise<Envelope<Thesis[]>>;
|
|
650
|
+
/** Iterates over every reply of a thesis. */
|
|
651
|
+
iterThesisReplies(params: ThesisRepliesParams): AsyncGenerator<Thesis, void, void>;
|
|
652
|
+
/** GET /v1/theses/latest — newest theses on every token (or only your users'). */
|
|
653
|
+
latestTheses(params?: LatestThesesParams): Promise<Thesis[]>;
|
|
654
|
+
latestThesesRaw(params?: LatestThesesParams): Promise<Envelope<Thesis[]>>;
|
|
655
|
+
/** GET /v1/theses/user — theses of one user, by csid_id or X username. */
|
|
656
|
+
userTheses(params: UserThesesParams): Promise<Thesis[]>;
|
|
657
|
+
userThesesRaw(params: UserThesesParams): Promise<Envelope<Thesis[]>>;
|
|
658
|
+
/**
|
|
659
|
+
* GET /v1/theses/eligibility — may this user post (holder, not paused) and
|
|
660
|
+
* reply on this token through your app? `reason` says why not
|
|
661
|
+
* (consent_required, plan_user_limit, sandbox_user).
|
|
662
|
+
*/
|
|
663
|
+
thesisEligibility(params: ThesisTokenParams & ThesisWriter): Promise<ThesisEligibility>;
|
|
664
|
+
/** POST /v1/theses — posts a thesis. Holders only (`not_a_holder` otherwise). */
|
|
665
|
+
postThesis(params: PostThesisParams): Promise<Thesis>;
|
|
666
|
+
/** POST /v1/theses/replies — replies to a thesis. */
|
|
667
|
+
replyToThesis(params: ReplyToThesisParams): Promise<Thesis>;
|
|
668
|
+
/** POST /v1/theses/reactions — adds (or with `on: false` removes) a reaction. */
|
|
669
|
+
reactToThesis(params: ReactToThesisParams): Promise<ThesisReactions>;
|
|
670
|
+
/** POST /v1/theses/report — reports a post (hidden for review after 3 reports). */
|
|
671
|
+
reportThesis(params: ReportThesisParams): Promise<{
|
|
672
|
+
reported: true;
|
|
673
|
+
}>;
|
|
674
|
+
/**
|
|
675
|
+
* GET /v1/theses/notifications — moderation notifications of one of your users
|
|
676
|
+
* (warnings, hidden posts, pauses, appeal results), with the unread count.
|
|
677
|
+
*/
|
|
678
|
+
thesisNotifications(csidId: string): Promise<ThesisNotifications>;
|
|
679
|
+
/**
|
|
680
|
+
* POST /v1/theses/appeal — appeals a moderation decision in the user's name
|
|
681
|
+
* (an `appealable` notification, within 30 days; message 10-1000 characters).
|
|
682
|
+
*/
|
|
683
|
+
appealThesisDecision(csidId: string, notificationId: number, message: string): Promise<{
|
|
684
|
+
appealed: true;
|
|
685
|
+
}>;
|
|
686
|
+
/** POST /v1/theses/delete — deletes the user's own thesis or reply. */
|
|
687
|
+
deleteThesis(params: DeleteThesisParams): Promise<{
|
|
688
|
+
deleted: true;
|
|
689
|
+
}>;
|
|
690
|
+
/**
|
|
691
|
+
* Live trades of your users over WebSocket (Pro plan and up).
|
|
692
|
+
*
|
|
693
|
+
* const stream = csid.stream({ blockchain: 'solana' });
|
|
694
|
+
* stream.on('trade', (trade) => console.log(trade));
|
|
695
|
+
* await stream.connect();
|
|
696
|
+
*/
|
|
697
|
+
stream(options?: StreamOptions): CabalSpyIDStream;
|
|
698
|
+
/**
|
|
699
|
+
* Live theses for the tokens you subscribe to (every plan), e.g. for a chart.
|
|
700
|
+
*
|
|
701
|
+
* const ts = csid.thesesStream();
|
|
702
|
+
* ts.on('thesis', (t) => addMarker(t));
|
|
703
|
+
* await ts.connect();
|
|
704
|
+
* ts.subscribe([{ blockchain: 'solana', mint }]);
|
|
705
|
+
*/
|
|
706
|
+
thesesStream(options?: ThesesStreamOptions): ThesesStream;
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
type HeaderSource = Headers | Record<string, string | string[] | undefined> | {
|
|
710
|
+
get(name: string): string | null | undefined;
|
|
711
|
+
};
|
|
712
|
+
interface VerifyWebhookOptions {
|
|
713
|
+
/** The raw request body, exactly as received (do not re-serialize parsed JSON). */
|
|
714
|
+
payload: string | Uint8Array | ArrayBuffer;
|
|
715
|
+
/** Request headers (Fetch Headers, Node's IncomingHttpHeaders or a plain object). */
|
|
716
|
+
headers: HeaderSource;
|
|
717
|
+
/** Signing secret from the dashboard, `whsec_…`. */
|
|
718
|
+
secret: string;
|
|
719
|
+
/** Maximum age (and future skew) of webhook-timestamp in seconds. Default: 300 */
|
|
720
|
+
toleranceSeconds?: number;
|
|
721
|
+
/** Current time in seconds; for tests. */
|
|
722
|
+
now?: number;
|
|
723
|
+
}
|
|
724
|
+
/**
|
|
725
|
+
* Computes the `webhook-signature` header value for a payload. Useful to
|
|
726
|
+
* build test requests for your receiver.
|
|
727
|
+
*/
|
|
728
|
+
declare function signWebhook(secret: string, id: string, timestamp: number, payload: string | Uint8Array): Promise<string>;
|
|
729
|
+
/**
|
|
730
|
+
* Verifies a webhook and returns the parsed event. Throws
|
|
731
|
+
* WebhookVerificationError when a header is missing, the timestamp is outside
|
|
732
|
+
* the tolerance or no signature matches.
|
|
733
|
+
*
|
|
734
|
+
* const event = await verifyWebhook({ payload: rawBody, headers: req.headers, secret: process.env.CSID_WEBHOOK_SECRET });
|
|
735
|
+
*/
|
|
736
|
+
declare function verifyWebhook<D = Record<string, unknown>>(options: VerifyWebhookOptions): Promise<WebhookEvent<D>>;
|
|
737
|
+
|
|
738
|
+
/** Internal helpers: encoding, WebCrypto access, environment. */
|
|
739
|
+
declare const SDK_VERSION = "0.5.2";
|
|
740
|
+
|
|
741
|
+
/**
|
|
742
|
+
* People can sign in with X, Telegram or Google. Accounts without X have no
|
|
743
|
+
* X profile: `x` is null, `twitter` is null and the handle is `tg.<name>`
|
|
744
|
+
* (Telegram) or `id.<hex>` (Google). X handles never contain a dot.
|
|
745
|
+
*/
|
|
746
|
+
/** Anything that describes a CabalSpy ID user: claims, a Data API profile, a trader or thesis author. */
|
|
747
|
+
interface UserLike {
|
|
748
|
+
x?: unknown;
|
|
749
|
+
twitter?: string | null;
|
|
750
|
+
preferred_username?: string | null;
|
|
751
|
+
username?: string | null;
|
|
752
|
+
}
|
|
753
|
+
/** The sign-in identity a handle belongs to. */
|
|
754
|
+
type HandleKind = 'x' | 'telegram' | 'google';
|
|
755
|
+
/** Which identity a CabalSpy ID handle comes from: `tg.` = Telegram, `id.` = Google, else X. */
|
|
756
|
+
declare function handleKind(handle: string): HandleKind;
|
|
757
|
+
/**
|
|
758
|
+
* True when the user has an X account connected.
|
|
759
|
+
*
|
|
760
|
+
* Uses the most reliable field available: `x` (userinfo claims, Data API
|
|
761
|
+
* profiles), then `twitter` (trading profiles, leaderboards), then the handle
|
|
762
|
+
* (ID token claims, thesis authors). Returns false for null/undefined. The ID
|
|
763
|
+
* token carries no `x` claim, so there the handle decides.
|
|
764
|
+
*/
|
|
765
|
+
declare function hasX(user: UserLike | null | undefined): boolean;
|
|
766
|
+
|
|
767
|
+
export { type ThesisStreamEvent as $, type ApiErrorBody as A, BadRequestError as B, CabalSpyID as C, DEFAULT_BASE_URL as D, type Envelope as E, type StreamEvent as F, type StreamEventMap as G, type HandleKind as H, InvalidResponseError as I, type StreamOptions as J, type StreamTopic as K, type LatestThesesParams as L, MAX_THESES_STREAM_TOKENS as M, NotFoundError as N, OAuthError as O, PermissionError as P, type Query as Q, RateLimitError as R, SDK_VERSION as S, type SubscribedEvent as T, type ThesesReadyEvent as U, ThesesStream as V, type ThesesStreamEventMap as W, type ThesesStreamOptions as X, type ThesesSubscribedEvent as Y, type ThesisRepliesParams as Z, type ThesisScopeParam as _, AuthenticationError as a, type ThesisTokenParams as a0, type ThesisTokenRef as a1, type ThesisWriter as a2, TokenVerificationError as a3, type TrackerParams as a4, type UserLike as a5, type UserThesesParams as a6, type UsersParams as a7, type VerifyWebhookOptions as a8, type WalletParams as a9, WebhookVerificationError as aa, handleKind as ab, hasX as ac, signWebhook as ad, verifyWebhook as ae, CabalSpyIDError as b, type CabalSpyIDErrorOptions as c, type CabalSpyIDOptions as d, CabalSpyIDStream as e, type CloseEvent as f, ConnectionError as g, DEFAULT_STREAM_URL as h, DEFAULT_THESES_STREAM_URL as i, type DeleteThesisParams as j, type HeaderSource as k, type HeartbeatEvent as l, type HistoryParams as m, type LatestTransactionsParams as n, type LeaderboardParams as o, type ListThesesParams as p, PlanUserLimitError as q, type PostThesisParams as r, type ProfileParams as s, type RateLimitInfo as t, type ReactToThesisParams as u, type ReconnectEvent as v, type ReplyToThesisParams as w, type ReportThesisParams as x, type ScopedParams as y, ServerError as z };
|