crawd 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/README.md +176 -0
  2. package/dist/cli.d.ts +1 -0
  3. package/dist/cli.js +975 -0
  4. package/dist/client.d.ts +53 -0
  5. package/dist/client.js +40 -0
  6. package/dist/types.d.ts +86 -0
  7. package/dist/types.js +0 -0
  8. package/openclaw.plugin.json +108 -0
  9. package/package.json +86 -0
  10. package/skills/crawd/SKILL.md +81 -0
  11. package/src/backend/coordinator.ts +883 -0
  12. package/src/backend/index.ts +581 -0
  13. package/src/backend/server.ts +589 -0
  14. package/src/cli.ts +130 -0
  15. package/src/client.ts +101 -0
  16. package/src/commands/auth.ts +145 -0
  17. package/src/commands/config.ts +43 -0
  18. package/src/commands/down.ts +15 -0
  19. package/src/commands/logs.ts +32 -0
  20. package/src/commands/skill.ts +189 -0
  21. package/src/commands/start.ts +120 -0
  22. package/src/commands/status.ts +73 -0
  23. package/src/commands/stop.ts +16 -0
  24. package/src/commands/stream-key.ts +45 -0
  25. package/src/commands/talk.ts +30 -0
  26. package/src/commands/up.ts +59 -0
  27. package/src/commands/update.ts +92 -0
  28. package/src/config/schema.ts +66 -0
  29. package/src/config/store.ts +185 -0
  30. package/src/daemon/manager.ts +280 -0
  31. package/src/daemon/pid.ts +102 -0
  32. package/src/lib/chat/base.ts +13 -0
  33. package/src/lib/chat/manager.ts +105 -0
  34. package/src/lib/chat/pumpfun/client.ts +56 -0
  35. package/src/lib/chat/types.ts +48 -0
  36. package/src/lib/chat/youtube/client.ts +131 -0
  37. package/src/lib/pumpfun/live/client.ts +69 -0
  38. package/src/lib/pumpfun/live/index.ts +3 -0
  39. package/src/lib/pumpfun/live/types.ts +38 -0
  40. package/src/lib/pumpfun/v2/client.ts +139 -0
  41. package/src/lib/pumpfun/v2/index.ts +5 -0
  42. package/src/lib/pumpfun/v2/socket/client.ts +60 -0
  43. package/src/lib/pumpfun/v2/socket/index.ts +6 -0
  44. package/src/lib/pumpfun/v2/socket/types.ts +7 -0
  45. package/src/lib/pumpfun/v2/types.ts +234 -0
  46. package/src/lib/tts/tiktok.ts +91 -0
  47. package/src/plugin.ts +280 -0
  48. package/src/types.ts +78 -0
  49. package/src/utils/logger.ts +43 -0
  50. package/src/utils/paths.ts +55 -0
@@ -0,0 +1,131 @@
1
+ import { Masterchat, stringify } from '@stu43005/masterchat'
2
+ import { BaseChatClient } from '../base'
3
+ import { generateShortId } from '../types'
4
+ import type { ChatPlatform, ChatMessage } from '../types'
5
+
6
+ /**
7
+ * YouTube Live Chat client using masterchat (no API credentials needed).
8
+ */
9
+ export class YouTubeChatClient extends BaseChatClient {
10
+ readonly platform: ChatPlatform = 'youtube'
11
+
12
+ private mc: Masterchat | null = null
13
+ private _connected = false
14
+ private videoId: string
15
+
16
+ // Deduplication: sliding window of recent IDs
17
+ private recentIds: string[] = []
18
+ private readonly maxRecentIds = 500
19
+
20
+ constructor(videoIdOrUrl: string) {
21
+ super()
22
+ this.videoId = this.extractVideoId(videoIdOrUrl)
23
+ }
24
+
25
+ async connect(): Promise<void> {
26
+ this.mc = await Masterchat.init(this.videoId)
27
+
28
+ this.mc.on('chat', (chat) => {
29
+ const prefixedId = `yt:${chat.id}`
30
+ if (this.recentIds.includes(prefixedId)) return
31
+ this.trackId(prefixedId)
32
+
33
+ const msg: ChatMessage = {
34
+ id: prefixedId,
35
+ shortId: generateShortId(),
36
+ platform: 'youtube',
37
+ username: chat.authorName ?? 'Anonymous',
38
+ message: chat.message ? stringify(chat.message) : '',
39
+ timestamp: chat.timestamp?.getTime() ?? Date.now(),
40
+ metadata: {
41
+ channelId: chat.authorChannelId,
42
+ isModerator: chat.isModerator,
43
+ isMember: !!chat.membership,
44
+ avatarUrl: chat.authorPhoto,
45
+ }
46
+ }
47
+
48
+ this.emit('message', msg)
49
+ })
50
+
51
+ // Handle super chats via actions event
52
+ this.mc.on('actions', (actions) => {
53
+ for (const action of actions) {
54
+ if (action.type !== 'addSuperChatItemAction') continue
55
+
56
+ const prefixedId = `yt:${action.id}`
57
+ if (this.recentIds.includes(prefixedId)) continue
58
+ this.trackId(prefixedId)
59
+
60
+ const msg: ChatMessage = {
61
+ id: prefixedId,
62
+ shortId: generateShortId(),
63
+ platform: 'youtube',
64
+ username: action.authorName ?? 'Anonymous',
65
+ message: action.message ? stringify(action.message) : '',
66
+ timestamp: action.timestamp?.getTime() ?? Date.now(),
67
+ metadata: {
68
+ channelId: action.authorChannelId,
69
+ isModerator: action.isModerator,
70
+ isMember: !!action.membership,
71
+ avatarUrl: action.authorPhoto,
72
+ superChat: {
73
+ amountDisplayString: `${action.currency}${action.amount}`,
74
+ backgroundColor: action.color ?? 'blue'
75
+ }
76
+ }
77
+ }
78
+
79
+ this.emit('message', msg)
80
+ }
81
+ })
82
+
83
+ this.mc.on('error', (err) => {
84
+ console.error('[YouTube] Chat error:', err)
85
+ this.emit('error', err)
86
+ })
87
+
88
+ this.mc.on('end', () => {
89
+ this._connected = false
90
+ this.emit('disconnected')
91
+ })
92
+
93
+ this.mc.listen()
94
+ this._connected = true
95
+ this.emit('connected')
96
+ }
97
+
98
+ disconnect(): void {
99
+ this.mc?.stop()
100
+ this.mc = null
101
+ this._connected = false
102
+ }
103
+
104
+ isConnected(): boolean {
105
+ return this._connected
106
+ }
107
+
108
+ /** Update video ID for new stream without recreating client */
109
+ setVideoId(videoIdOrUrl: string): void {
110
+ this.videoId = this.extractVideoId(videoIdOrUrl)
111
+ }
112
+
113
+ private extractVideoId(input: string): string {
114
+ const patterns = [
115
+ /(?:v=|youtu\.be\/|\/live\/)([a-zA-Z0-9_-]{11})/,
116
+ /^([a-zA-Z0-9_-]{11})$/
117
+ ]
118
+ for (const pattern of patterns) {
119
+ const match = input.match(pattern)
120
+ if (match) return match[1]
121
+ }
122
+ return input
123
+ }
124
+
125
+ private trackId(id: string): void {
126
+ this.recentIds.push(id)
127
+ if (this.recentIds.length > this.maxRecentIds) {
128
+ this.recentIds.shift()
129
+ }
130
+ }
131
+ }
@@ -0,0 +1,69 @@
1
+ import type {
2
+ PumpfunCurrentlyLiveResponse,
3
+ PumpfunJoinLivestreamResponse,
4
+ PumpfunLivestreamConnection,
5
+ } from "./types";
6
+ import { PumpfunLiveStreamSocketUrl } from "./types";
7
+
8
+ export class Pumpfun {
9
+ public async getLivestream(
10
+ mint: string,
11
+ ): Promise<PumpfunLivestreamConnection> {
12
+ const url = `https://livestream-api.pump.fun/livestream/join`;
13
+
14
+ try {
15
+ const [joinResponse, currentlyLiveData] = await Promise.all([
16
+ fetch(url, {
17
+ method: "POST",
18
+ headers: {
19
+ "Content-Type": "application/json",
20
+ },
21
+ body: JSON.stringify({
22
+ mintId: mint,
23
+ viewer: true,
24
+ hidden: true,
25
+ }),
26
+ }),
27
+ this.getLivestreams(),
28
+ ]);
29
+
30
+ if (!joinResponse.ok) {
31
+ throw new Error(
32
+ `Failed to fetch livestreams: ${joinResponse.status} ${joinResponse.statusText}`,
33
+ );
34
+ }
35
+
36
+ const data = (await joinResponse.json()) as PumpfunJoinLivestreamResponse;
37
+
38
+ const livestreamData = currentlyLiveData.find(
39
+ (stream) => stream.mint === mint,
40
+ );
41
+
42
+ return {
43
+ token: data.token,
44
+ websocketUrl: PumpfunLiveStreamSocketUrl,
45
+ livestreamData,
46
+ };
47
+ } catch (error) {
48
+ throw error;
49
+ }
50
+ }
51
+
52
+ public async getLivestreams(): Promise<PumpfunCurrentlyLiveResponse> {
53
+ const url = `https://frontend-api-v3.pump.fun/coins/currently-live?offset=0&limit=1000&sort=currently_live&order=DESC&includeNsfw=true`;
54
+
55
+ try {
56
+ const response = await fetch(url);
57
+
58
+ if (!response.ok) {
59
+ throw new Error(
60
+ `Failed to fetch livestreams: ${response.status} ${response.statusText}`,
61
+ );
62
+ }
63
+
64
+ return (await response.json()) as PumpfunCurrentlyLiveResponse;
65
+ } catch (error) {
66
+ throw error;
67
+ }
68
+ }
69
+ }
@@ -0,0 +1,3 @@
1
+ import { Pumpfun } from "./client";
2
+
3
+ export const pumpfun = new Pumpfun();
@@ -0,0 +1,38 @@
1
+ export const PumpfunLiveStreamSocketUrl =
2
+ "wss://pump-prod-tg2x8veh.livekit.cloud/rtc";
3
+
4
+ export type PumpfunLivestreamConnection = {
5
+ websocketUrl: string;
6
+ token: string;
7
+ livestreamData?: PumpfunLivestream;
8
+ };
9
+
10
+ export type PumpfunLivestream = {
11
+ mint: string;
12
+ name: string;
13
+ symbol: string;
14
+ description: string;
15
+ image_uri: string;
16
+ metadata_uri: string;
17
+ twitter: string | null;
18
+ telegram: string | null;
19
+ bonding_curve: string;
20
+ creator: string;
21
+ created_timestamp: number;
22
+ raydium_pool: string;
23
+ num_participants: number;
24
+ complete: boolean;
25
+ thumbnail: string;
26
+ market_id: string;
27
+ usd_market_cap: number;
28
+ is_currently_live: boolean;
29
+ reply_count: number;
30
+ market_cap: number; // usd
31
+ };
32
+
33
+ export type PumpfunCurrentlyLiveResponse = PumpfunLivestream[];
34
+
35
+ export type PumpfunJoinLivestreamResponse = {
36
+ token: string;
37
+ role: string;
38
+ };
@@ -0,0 +1,139 @@
1
+ import {
2
+ Candle,
3
+ CandlesOptions,
4
+ CreatorFee,
5
+ CreatorFeesOptions,
6
+ FollowerInfo,
7
+ JoinLivestreamResponse,
8
+ Livestream,
9
+ LivestreamClipsOptions,
10
+ LivestreamClipsResponse,
11
+ MarketTradesResponse,
12
+ TotalFees,
13
+ UserProfile,
14
+ WalletBalances,
15
+ WalletBalancesOptions,
16
+ } from "./types";
17
+
18
+ export class PumpFunClient {
19
+ private readonly frontendApiBase = "https://frontend-api-v3.pump.fun";
20
+ private readonly swapApiBase = "https://swap-api.pump.fun";
21
+ private readonly livestreamApiBase = "https://livestream-api.pump.fun";
22
+
23
+ private async fetch<T>(url: string): Promise<T> {
24
+ const response = await fetch(url);
25
+ if (!response.ok) {
26
+ throw new Error(`HTTP error! status: ${response.status}`);
27
+ }
28
+ return response.json();
29
+ }
30
+
31
+ async getUserProfile(username: string): Promise<UserProfile> {
32
+ return this.fetch<UserProfile>(`${this.frontendApiBase}/users/${username}`);
33
+ }
34
+
35
+ async getFollowers(walletAddress: string): Promise<FollowerInfo[]> {
36
+ return this.fetch<FollowerInfo[]>(`${this.frontendApiBase}/following/followers/${walletAddress}`);
37
+ }
38
+
39
+ async getFollowing(walletAddress: string): Promise<FollowerInfo[]> {
40
+ return this.fetch<FollowerInfo[]>(`${this.frontendApiBase}/following/${walletAddress}`);
41
+ }
42
+
43
+ async getWalletBalances(walletAddress: string, options: WalletBalancesOptions = {}): Promise<WalletBalances> {
44
+ const params = new URLSearchParams();
45
+ if (options.includePnl !== undefined) {
46
+ params.append("includePnl", String(options.includePnl));
47
+ }
48
+ if (options.page !== undefined) {
49
+ params.append("page", String(options.page));
50
+ }
51
+ if (options.limit !== undefined) {
52
+ params.append("limit", String(options.limit));
53
+ }
54
+ const queryString = params.toString();
55
+ const url = `${this.swapApiBase}/v1/wallet/${walletAddress}/balances${queryString ? `?${queryString}` : ""}`;
56
+ return this.fetch<WalletBalances>(url);
57
+ }
58
+
59
+ async getCreatorFees(walletAddress: string, options: CreatorFeesOptions = {}): Promise<CreatorFee[]> {
60
+ const params = new URLSearchParams();
61
+ if (options.interval !== undefined) {
62
+ params.append("interval", options.interval);
63
+ }
64
+ if (options.limit !== undefined) {
65
+ params.append("limit", String(options.limit));
66
+ }
67
+ const queryString = params.toString();
68
+ const url = `${this.swapApiBase}/v1/creators/${walletAddress}/fees${queryString ? `?${queryString}` : ""}`;
69
+ return this.fetch<CreatorFee[]>(url);
70
+ }
71
+
72
+ async getTotalFees(walletAddress: string): Promise<TotalFees> {
73
+ return this.fetch<TotalFees>(`${this.swapApiBase}/v1/creators/${walletAddress}/fees/total`);
74
+ }
75
+
76
+ async getCoin(mint: string): Promise<Livestream> {
77
+ return this.fetch<Livestream>(`${this.frontendApiBase}/coins-v2/${mint}`);
78
+ }
79
+
80
+ async getCurrentLivestreams(): Promise<Livestream[]> {
81
+ return this.fetch<Livestream[]>(`${this.frontendApiBase}/coins-v2/currently-live`);
82
+ }
83
+
84
+ async getLivestreamClips(mint: string, options: LivestreamClipsOptions = {}): Promise<LivestreamClipsResponse> {
85
+ const params = new URLSearchParams();
86
+ if (options.limit !== undefined) {
87
+ params.append("limit", String(options.limit));
88
+ }
89
+ if (options.clipType !== undefined) {
90
+ params.append("clipType", options.clipType);
91
+ }
92
+ const queryString = params.toString();
93
+ const url = `${this.livestreamApiBase}/clips/${mint}${queryString ? `?${queryString}` : ""}`;
94
+ return this.fetch<LivestreamClipsResponse>(url);
95
+ }
96
+
97
+ async getMarketActivity(mint: string): Promise<MarketTradesResponse> {
98
+ return this.fetch<MarketTradesResponse>(`${this.swapApiBase}/v2/coins/${mint}/trades`);
99
+ }
100
+
101
+ async getCandles(mint: string, options: CandlesOptions = {}): Promise<Candle[]> {
102
+ const params = new URLSearchParams();
103
+ if (options.interval !== undefined) {
104
+ params.append("interval", options.interval);
105
+ }
106
+ if (options.limit !== undefined) {
107
+ params.append("limit", String(options.limit));
108
+ }
109
+ if (options.currency !== undefined) {
110
+ params.append("currency", options.currency);
111
+ }
112
+ if (options.createdTs !== undefined) {
113
+ params.append("createdTs", String(options.createdTs));
114
+ }
115
+ const qs = params.toString();
116
+ const url = `${this.swapApiBase}/v2/coins/${mint}/candles${qs ? `?${qs}` : ""}`;
117
+ return this.fetch<Candle[]>(url);
118
+ }
119
+
120
+ async joinLivestream(mint: string): Promise<JoinLivestreamResponse> {
121
+ const response = await fetch("https://livestream-api.pump.fun/livestream/join", {
122
+ method: "POST",
123
+ headers: {
124
+ "Content-Type": "application/json",
125
+ },
126
+ body: JSON.stringify({
127
+ mintId: mint,
128
+ viewer: true,
129
+ hidden: true,
130
+ }),
131
+ });
132
+
133
+ if (!response.ok) {
134
+ throw new Error(`Failed to join the livestream: ${response.status} ${response.statusText}`);
135
+ }
136
+
137
+ return (await response.json()) as JoinLivestreamResponse;
138
+ }
139
+ }
@@ -0,0 +1,5 @@
1
+ import { PumpFunClient } from "./client";
2
+
3
+ export * from "./types";
4
+
5
+ export const pumpfun = new PumpFunClient();
@@ -0,0 +1,60 @@
1
+ import { io, Socket } from "socket.io-client";
2
+ import { PumpfunMessage } from "./types";
3
+
4
+ export class PumpfunSocketClient {
5
+ private readonly socket: Socket;
6
+
7
+ constructor(authToken: string | null) {
8
+ this.socket = io("wss://livechat.pump.fun", {
9
+ path: "/socket.io/",
10
+ transports: ["websocket"],
11
+ autoConnect: false,
12
+ withCredentials: true,
13
+ extraHeaders: {
14
+ Host: "livechat.pump.fun",
15
+ Origin: "https://pump.fun",
16
+ },
17
+ });
18
+ }
19
+
20
+ connect(): void {
21
+ this.socket.connect();
22
+ }
23
+
24
+ disconnect(): void {
25
+ this.socket.disconnect();
26
+ }
27
+
28
+ async joinRoom(roomId: string): Promise<void> {
29
+ return new Promise((resolve) => {
30
+ this.socket.emit("joinRoom", { roomId, username: "" });
31
+ setTimeout(resolve, 200);
32
+ });
33
+ }
34
+
35
+ async sendMessage(roomId: string, message: string): Promise<void> {
36
+ this.socket.emit("sendMessage2", { roomId, message, username: "" });
37
+ }
38
+
39
+ async getMessagesHistory({
40
+ roomId,
41
+ limit,
42
+ }: {
43
+ roomId: string;
44
+ limit?: number;
45
+ }): Promise<PumpfunMessage[]> {
46
+ return new Promise((resolve) => {
47
+ this.socket.emit(
48
+ "getMessageHistory",
49
+ { roomId: roomId, before: null, limit: limit ?? 20 },
50
+ (messages: PumpfunMessage[]) => {
51
+ resolve(messages);
52
+ },
53
+ );
54
+ });
55
+ }
56
+
57
+ onMessage(callback: (message: PumpfunMessage) => void): void {
58
+ this.socket.on("newMessage", callback);
59
+ }
60
+ }
@@ -0,0 +1,6 @@
1
+ import dotenv from "dotenv";
2
+ import { PumpfunSocketClient } from "./client";
3
+
4
+ dotenv.config();
5
+
6
+ export const pumpfunSocketClient = new PumpfunSocketClient(process.env.PUMPFUN_AUTH_TOKEN!);
@@ -0,0 +1,7 @@
1
+ export interface PumpfunMessage {
2
+ id: string;
3
+ roomId: string;
4
+ message: string;
5
+ userAddress: string;
6
+ username: string;
7
+ }
@@ -0,0 +1,234 @@
1
+ export interface UserProfile {
2
+ address: string;
3
+ likes_received: number;
4
+ unread_notifs_count: number;
5
+ mentions_received: number;
6
+ username: string;
7
+ profile_image: string;
8
+ last_username_update_timestamp: number;
9
+ following: number;
10
+ followers: number;
11
+ bio: string;
12
+ x_username: string | null;
13
+ x_id: string | null;
14
+ }
15
+
16
+ export interface FollowerInfo {
17
+ username: string;
18
+ profile_image: string;
19
+ address: string;
20
+ timestamp: number;
21
+ followers: number;
22
+ }
23
+
24
+ export interface TokenCoin {
25
+ mint: string;
26
+ name: string;
27
+ symbol: string;
28
+ image_uri: string;
29
+ creator: string;
30
+ market_cap: number;
31
+ usd_market_cap: number;
32
+ }
33
+
34
+ export interface PnlInfo {
35
+ realized_pnl: {
36
+ percent: string;
37
+ usd: string;
38
+ };
39
+ unrealized_pnl: {
40
+ percent: string;
41
+ usd: string;
42
+ };
43
+ total_usd_in: string;
44
+ total_usd_out: string;
45
+ total_pnl: {
46
+ percent: string;
47
+ usd: string;
48
+ };
49
+ }
50
+
51
+ export interface HoldingToken {
52
+ mint: string;
53
+ balance: string;
54
+ price: string;
55
+ fetchedAt: string;
56
+ balanceUSD: string;
57
+ coin: TokenCoin;
58
+ pnl: PnlInfo;
59
+ }
60
+
61
+ export interface WalletBalances {
62
+ items: HoldingToken[];
63
+ total: number;
64
+ nextCursor: string;
65
+ nativeBalance: number;
66
+ itemCount: number;
67
+ totalBalanceUSD: number;
68
+ lastUpdated: string;
69
+ }
70
+
71
+ export interface CreatorFee {
72
+ bucket: string;
73
+ creatorFee: string;
74
+ creatorFeeSOL: string;
75
+ numTrades: number;
76
+ cumulativeCreatorFee: string;
77
+ cumulativeCreatorFeeSOL: string;
78
+ }
79
+
80
+ export interface TotalFees {
81
+ totalFees: string;
82
+ totalFeesSOL: string;
83
+ }
84
+
85
+ export interface Livestream {
86
+ mint: string;
87
+ name: string;
88
+ symbol: string;
89
+ description: string;
90
+ image_uri: string;
91
+ metadata_uri: string;
92
+ twitter: string | null;
93
+ telegram: string | null;
94
+ bonding_curve: string;
95
+ associated_bonding_curve: string;
96
+ creator: string;
97
+ created_timestamp: number;
98
+ raydium_pool: string | null;
99
+ complete: boolean;
100
+ virtual_sol_reserves: number;
101
+ virtual_token_reserves: number;
102
+ hidden: boolean | null;
103
+ total_supply: number;
104
+ website: string;
105
+ show_name: boolean;
106
+ last_trade_timestamp: number;
107
+ king_of_the_hill_timestamp: number;
108
+ market_cap: number;
109
+ nsfw: boolean;
110
+ market_id: string | null;
111
+ inverted: boolean;
112
+ real_sol_reserves: number;
113
+ real_token_reserves: number;
114
+ livestream_ban_expiry: number;
115
+ last_reply: number;
116
+ reply_count: number;
117
+ is_banned: boolean;
118
+ is_currently_live: boolean;
119
+ initialized: boolean;
120
+ video_uri: string | null;
121
+ updated_at: string | null;
122
+ pump_swap_pool: string;
123
+ ath_market_cap: number;
124
+ ath_market_cap_timestamp: number;
125
+ banner_uri: string;
126
+ hide_banner: boolean;
127
+ livestream_downrank_score: number;
128
+ program: string | null;
129
+ platform: string | null;
130
+ thumbnail: string;
131
+ thumbnail_updated_at: number;
132
+ num_participants: number;
133
+ downrank_score: number;
134
+ usd_market_cap: number;
135
+ }
136
+
137
+ export interface LivestreamClip {
138
+ roomName: string;
139
+ clipId: string;
140
+ sessionId: string;
141
+ startTime: string;
142
+ endTime: string;
143
+ duration: number;
144
+ playlistUrl: string;
145
+ mp4S3Key: string;
146
+ mp4SizeBytes: number;
147
+ mp4CreatedAt: string;
148
+ thumbnailUrl: string;
149
+ thumbnailS3Key: string;
150
+ playlistS3Key: string;
151
+ hidden: boolean;
152
+ clipType: string;
153
+ createdAt: string;
154
+ }
155
+
156
+ export interface LivestreamClipsResponse {
157
+ clips: LivestreamClip[];
158
+ }
159
+
160
+ export interface MarketActivityPeriod {
161
+ numTxs: number;
162
+ volumeUSD: number;
163
+ numUsers: number;
164
+ numBuys: number;
165
+ numSells: number;
166
+ buyVolumeUSD: number;
167
+ sellVolumeUSD: number;
168
+ numBuyers: number;
169
+ numSellers: number;
170
+ priceChangePercent: number;
171
+ }
172
+
173
+ export interface MarketActivity {
174
+ "5m": MarketActivityPeriod | null;
175
+ "1h": MarketActivityPeriod | null;
176
+ "6h": MarketActivityPeriod | null;
177
+ "24h": MarketActivityPeriod | null;
178
+ }
179
+
180
+ export interface WalletBalancesOptions {
181
+ includePnl?: boolean;
182
+ page?: number;
183
+ limit?: number;
184
+ }
185
+
186
+ export interface CreatorFeesOptions {
187
+ interval?: string;
188
+ limit?: number;
189
+ }
190
+
191
+ export interface LivestreamClipsOptions {
192
+ limit?: number;
193
+ clipType?: string;
194
+ }
195
+
196
+ export interface MarketTrade {
197
+ slotIndexId: string;
198
+ tx: string;
199
+ timestamp: string;
200
+ userAddress: string;
201
+ type: string;
202
+ program: string;
203
+ priceUsd: string;
204
+ priceSol: string;
205
+ amountUsd: string;
206
+ amountSol: string;
207
+ baseAmount: string;
208
+ quoteAmount: string;
209
+ }
210
+
211
+ export interface MarketTradesResponse {
212
+ trades: MarketTrade[];
213
+ }
214
+
215
+ export interface Candle {
216
+ timestamp: number;
217
+ open: string;
218
+ high: string;
219
+ low: string;
220
+ close: string;
221
+ volume: string;
222
+ }
223
+
224
+ export interface CandlesOptions {
225
+ interval?: string;
226
+ limit?: number;
227
+ currency?: string;
228
+ createdTs?: number;
229
+ }
230
+
231
+ export type JoinLivestreamResponse = {
232
+ token: string;
233
+ role: string;
234
+ };