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.
- package/README.md +176 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +975 -0
- package/dist/client.d.ts +53 -0
- package/dist/client.js +40 -0
- package/dist/types.d.ts +86 -0
- package/dist/types.js +0 -0
- package/openclaw.plugin.json +108 -0
- package/package.json +86 -0
- package/skills/crawd/SKILL.md +81 -0
- package/src/backend/coordinator.ts +883 -0
- package/src/backend/index.ts +581 -0
- package/src/backend/server.ts +589 -0
- package/src/cli.ts +130 -0
- package/src/client.ts +101 -0
- package/src/commands/auth.ts +145 -0
- package/src/commands/config.ts +43 -0
- package/src/commands/down.ts +15 -0
- package/src/commands/logs.ts +32 -0
- package/src/commands/skill.ts +189 -0
- package/src/commands/start.ts +120 -0
- package/src/commands/status.ts +73 -0
- package/src/commands/stop.ts +16 -0
- package/src/commands/stream-key.ts +45 -0
- package/src/commands/talk.ts +30 -0
- package/src/commands/up.ts +59 -0
- package/src/commands/update.ts +92 -0
- package/src/config/schema.ts +66 -0
- package/src/config/store.ts +185 -0
- package/src/daemon/manager.ts +280 -0
- package/src/daemon/pid.ts +102 -0
- package/src/lib/chat/base.ts +13 -0
- package/src/lib/chat/manager.ts +105 -0
- package/src/lib/chat/pumpfun/client.ts +56 -0
- package/src/lib/chat/types.ts +48 -0
- package/src/lib/chat/youtube/client.ts +131 -0
- package/src/lib/pumpfun/live/client.ts +69 -0
- package/src/lib/pumpfun/live/index.ts +3 -0
- package/src/lib/pumpfun/live/types.ts +38 -0
- package/src/lib/pumpfun/v2/client.ts +139 -0
- package/src/lib/pumpfun/v2/index.ts +5 -0
- package/src/lib/pumpfun/v2/socket/client.ts +60 -0
- package/src/lib/pumpfun/v2/socket/index.ts +6 -0
- package/src/lib/pumpfun/v2/socket/types.ts +7 -0
- package/src/lib/pumpfun/v2/types.ts +234 -0
- package/src/lib/tts/tiktok.ts +91 -0
- package/src/plugin.ts +280 -0
- package/src/types.ts +78 -0
- package/src/utils/logger.ts +43 -0
- 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,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,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,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
|
+
};
|