@solworks/poll-api-client 0.1.0 → 0.1.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/dist/client.js +46 -17
- package/dist/types.d.ts +9 -5
- package/package.json +1 -1
- package/tests/unit/endpoints/bets.test.ts +15 -9
- package/tests/unit/endpoints/leaderboard.test.ts +6 -2
- package/tests/unit/endpoints/social.test.ts +7 -6
- package/tests/unit/endpoints/user.test.ts +27 -10
- package/tests/unit/endpoints/wallet.test.ts +3 -2
package/dist/client.js
CHANGED
|
@@ -72,11 +72,15 @@ export class PollClient {
|
|
|
72
72
|
}
|
|
73
73
|
// ── User ──────────────────────────────────────────────────────────────
|
|
74
74
|
async getAccount() {
|
|
75
|
-
|
|
75
|
+
// API returns { user: {...}, address: string, error: null }
|
|
76
|
+
const res = await this.request('GET', '/api/user/account');
|
|
77
|
+
return { ...res.user, walletAddress: res.address };
|
|
76
78
|
}
|
|
77
79
|
async getProfile(uuid) {
|
|
80
|
+
// API returns { profile: {...}, stats: {...}, error: null }
|
|
78
81
|
const path = uuid ? `/api/user/profile/${uuid}` : '/api/user/profile';
|
|
79
|
-
|
|
82
|
+
const res = await this.request('GET', path);
|
|
83
|
+
return { ...res.profile, stats: res.stats };
|
|
80
84
|
}
|
|
81
85
|
async updateDisplayName(name) {
|
|
82
86
|
await this.request('POST', '/api/user/account/displayname', {
|
|
@@ -84,30 +88,40 @@ export class PollClient {
|
|
|
84
88
|
});
|
|
85
89
|
}
|
|
86
90
|
async getXpBalance() {
|
|
91
|
+
// API returns { xp: number, error: null }
|
|
87
92
|
return this.request('GET', '/api/user/balance');
|
|
88
93
|
}
|
|
89
94
|
async getUsdcBalance() {
|
|
90
|
-
|
|
95
|
+
// API returns { balance: number, error: null } — field is "balance", not "usdc"
|
|
96
|
+
const res = await this.request('GET', '/api/user/usdc/balance');
|
|
97
|
+
return { usdc: res.balance, error: res.error };
|
|
91
98
|
}
|
|
92
99
|
// ── Bets ──────────────────────────────────────────────────────────────
|
|
100
|
+
// Bets endpoints use ResponseBuilder: { data: T, error: {...}, request: {...} }
|
|
93
101
|
async listPublicBets(params) {
|
|
94
102
|
const path = this.buildUrl('/api/bets-usdc/all/public', params);
|
|
95
|
-
|
|
103
|
+
const res = await this.request('GET', path);
|
|
104
|
+
return res.data;
|
|
96
105
|
}
|
|
97
106
|
async getTrendingBets() {
|
|
98
|
-
|
|
107
|
+
const res = await this.request('GET', '/api/bets-usdc/all/public/trending');
|
|
108
|
+
return res.data;
|
|
99
109
|
}
|
|
100
110
|
async getNewBets() {
|
|
101
|
-
|
|
111
|
+
const res = await this.request('GET', '/api/bets-usdc/all/public/new');
|
|
112
|
+
return res.data;
|
|
102
113
|
}
|
|
103
114
|
async getBet(id) {
|
|
104
|
-
|
|
115
|
+
const res = await this.request('GET', `/api/bets-usdc/all/public/single/${id}`);
|
|
116
|
+
return res.data;
|
|
105
117
|
}
|
|
106
118
|
async getMyBets() {
|
|
107
|
-
|
|
119
|
+
const res = await this.request('GET', '/api/bets-usdc/mine');
|
|
120
|
+
return res.data;
|
|
108
121
|
}
|
|
109
122
|
async createBet(params) {
|
|
110
|
-
|
|
123
|
+
const res = await this.request('POST', '/api/bets-usdc', params);
|
|
124
|
+
return res.data;
|
|
111
125
|
}
|
|
112
126
|
async joinBet(betAddress) {
|
|
113
127
|
return this.request('POST', '/api/bets-usdc/join', { betAddress });
|
|
@@ -130,33 +144,44 @@ export class PollClient {
|
|
|
130
144
|
return this.request('POST', '/api/bets-usdc/settle', { betAddress });
|
|
131
145
|
}
|
|
132
146
|
async getProbabilityHistory(betAddress) {
|
|
133
|
-
|
|
147
|
+
// API returns { data: { betAddress, dataPoints: [...] } }
|
|
148
|
+
const res = await this.request('GET', `/api/bets-usdc/all/public/single/${betAddress}/probability-history`);
|
|
149
|
+
return res.data.dataPoints;
|
|
134
150
|
}
|
|
135
151
|
// ── Wagers ────────────────────────────────────────────────────────────
|
|
136
152
|
async getMyWagers(params) {
|
|
153
|
+
// API returns { data: [...], error: {...}, request: {...} }
|
|
137
154
|
const path = this.buildUrl('/api/bets-usdc/wagers', params);
|
|
138
|
-
|
|
155
|
+
const res = await this.request('GET', path);
|
|
156
|
+
return res.data;
|
|
139
157
|
}
|
|
140
158
|
// ── Leaderboard ───────────────────────────────────────────────────────
|
|
141
159
|
async getLeaderboard() {
|
|
142
|
-
|
|
160
|
+
// API returns { leaderboard: [...], pagination: {...} }
|
|
161
|
+
const res = await this.request('GET', '/api/leaderboard');
|
|
162
|
+
return res.leaderboard;
|
|
143
163
|
}
|
|
144
164
|
async getMyRanking() {
|
|
145
165
|
return this.request('GET', '/api/leaderboard/me');
|
|
146
166
|
}
|
|
147
167
|
// ── Social ────────────────────────────────────────────────────────────
|
|
148
168
|
async getFriends() {
|
|
149
|
-
|
|
169
|
+
// API returns { friends: [...], totalCount, error }
|
|
170
|
+
const res = await this.request('GET', '/api/user/friends');
|
|
171
|
+
return res.friends;
|
|
150
172
|
}
|
|
151
173
|
async sendFriendRequest(uuid) {
|
|
152
|
-
|
|
174
|
+
// API expects { targetUserUuid } not { uuid }
|
|
175
|
+
return this.request('POST', '/api/user/friends/request', { targetUserUuid: uuid });
|
|
153
176
|
}
|
|
154
177
|
async respondFriendRequest(id, accept) {
|
|
155
178
|
const action = accept ? 'accept' : 'decline';
|
|
156
179
|
return this.request('PUT', `/api/user/friends/request/${id}/${action}`);
|
|
157
180
|
}
|
|
158
181
|
async getFavouriteBets() {
|
|
159
|
-
|
|
182
|
+
// API returns { data: [...], error }
|
|
183
|
+
const res = await this.request('GET', '/api/user/favourites/bets');
|
|
184
|
+
return res.data;
|
|
160
185
|
}
|
|
161
186
|
async favouriteBet(betAddress) {
|
|
162
187
|
return this.request('POST', '/api/user/favourites/bets', {
|
|
@@ -171,12 +196,16 @@ export class PollClient {
|
|
|
171
196
|
}
|
|
172
197
|
// ── Wallet ────────────────────────────────────────────────────────────
|
|
173
198
|
async getWalletTransactions() {
|
|
174
|
-
|
|
199
|
+
// API returns { transactions: [...], error }
|
|
200
|
+
const res = await this.request('GET', '/api/user/wallet/transactions');
|
|
201
|
+
return res.transactions;
|
|
175
202
|
}
|
|
176
203
|
// ── Notifications ─────────────────────────────────────────────────────
|
|
177
204
|
async getNotifications(params) {
|
|
205
|
+
// API returns { notifications: [...], unreadCount, totalCount, page, limit, hasMore, error }
|
|
178
206
|
const path = this.buildUrl('/api/user/notifications', params);
|
|
179
|
-
|
|
207
|
+
const res = await this.request('GET', path);
|
|
208
|
+
return res.notifications;
|
|
180
209
|
}
|
|
181
210
|
async markNotificationRead(id) {
|
|
182
211
|
return this.request('POST', '/api/user/notification/read', {
|
package/dist/types.d.ts
CHANGED
|
@@ -22,16 +22,18 @@ export interface UserAccount {
|
|
|
22
22
|
email: string | null;
|
|
23
23
|
xpBalance: number;
|
|
24
24
|
balance: number;
|
|
25
|
+
walletAddress?: string;
|
|
25
26
|
[key: string]: unknown;
|
|
26
27
|
}
|
|
27
28
|
export interface UserProfile {
|
|
28
|
-
id: number;
|
|
29
29
|
uuid: string;
|
|
30
30
|
displayName: string | null;
|
|
31
|
+
profileImageUrl: string | null;
|
|
32
|
+
stats?: Record<string, unknown>;
|
|
31
33
|
[key: string]: unknown;
|
|
32
34
|
}
|
|
33
35
|
export interface Balance {
|
|
34
|
-
xp
|
|
36
|
+
xp?: number;
|
|
35
37
|
usdc?: number;
|
|
36
38
|
error: string | null;
|
|
37
39
|
}
|
|
@@ -55,6 +57,8 @@ export interface Friend {
|
|
|
55
57
|
id: number;
|
|
56
58
|
uuid: string;
|
|
57
59
|
displayName: string | null;
|
|
60
|
+
profileImageUrl: string | null;
|
|
61
|
+
friendsSince?: string;
|
|
58
62
|
[key: string]: unknown;
|
|
59
63
|
}
|
|
60
64
|
export interface WalletTransaction {
|
|
@@ -66,10 +70,10 @@ export interface WalletTransaction {
|
|
|
66
70
|
}
|
|
67
71
|
export interface Notification {
|
|
68
72
|
id: string;
|
|
69
|
-
|
|
73
|
+
eventType: string;
|
|
70
74
|
title: string;
|
|
71
|
-
|
|
72
|
-
|
|
75
|
+
description?: string;
|
|
76
|
+
readAt: string | null;
|
|
73
77
|
createdAt: string;
|
|
74
78
|
[key: string]: unknown;
|
|
75
79
|
}
|
package/package.json
CHANGED
|
@@ -3,6 +3,12 @@ import { PollClient } from '../../../src/client';
|
|
|
3
3
|
import { createMockFetch, mockJsonResponse } from '../../helpers/mock-fetch';
|
|
4
4
|
import { createBetFixture } from '../../fixtures';
|
|
5
5
|
|
|
6
|
+
// API bets endpoints return ResponseBuilder.success() wrapper:
|
|
7
|
+
// { data: T, error: { message: null, logs: [] }, request: { uuid, latency } }
|
|
8
|
+
function wrapResponse<T>(data: T) {
|
|
9
|
+
return { data, error: { message: null, logs: [] }, request: { uuid: 'req-123', latency: 10 } };
|
|
10
|
+
}
|
|
11
|
+
|
|
6
12
|
describe('Bets endpoints', () => {
|
|
7
13
|
let mockFetch: ReturnType<typeof createMockFetch>;
|
|
8
14
|
let client: PollClient;
|
|
@@ -16,9 +22,9 @@ describe('Bets endpoints', () => {
|
|
|
16
22
|
});
|
|
17
23
|
});
|
|
18
24
|
|
|
19
|
-
it('listPublicBets sends correct GET', async () => {
|
|
25
|
+
it('listPublicBets sends correct GET and unwraps data', async () => {
|
|
20
26
|
const bets = [createBetFixture(), createBetFixture()];
|
|
21
|
-
mockFetch.mockResolvedValue(mockJsonResponse(bets));
|
|
27
|
+
mockFetch.mockResolvedValue(mockJsonResponse(wrapResponse(bets)));
|
|
22
28
|
|
|
23
29
|
const result = await client.listPublicBets();
|
|
24
30
|
|
|
@@ -30,7 +36,7 @@ describe('Bets endpoints', () => {
|
|
|
30
36
|
|
|
31
37
|
it('listPublicBets with page param', async () => {
|
|
32
38
|
const bets = [createBetFixture()];
|
|
33
|
-
mockFetch.mockResolvedValue(mockJsonResponse(bets));
|
|
39
|
+
mockFetch.mockResolvedValue(mockJsonResponse(wrapResponse(bets)));
|
|
34
40
|
|
|
35
41
|
await client.listPublicBets({ page: 2 });
|
|
36
42
|
|
|
@@ -38,9 +44,9 @@ describe('Bets endpoints', () => {
|
|
|
38
44
|
expect(url).toBe('https://api.poll.fun/api/bets-usdc/all/public?page=2');
|
|
39
45
|
});
|
|
40
46
|
|
|
41
|
-
it('getTrendingBets sends correct GET', async () => {
|
|
47
|
+
it('getTrendingBets sends correct GET and unwraps data', async () => {
|
|
42
48
|
const bets = [createBetFixture()];
|
|
43
|
-
mockFetch.mockResolvedValue(mockJsonResponse(bets));
|
|
49
|
+
mockFetch.mockResolvedValue(mockJsonResponse(wrapResponse(bets)));
|
|
44
50
|
|
|
45
51
|
const result = await client.getTrendingBets();
|
|
46
52
|
|
|
@@ -50,9 +56,9 @@ describe('Bets endpoints', () => {
|
|
|
50
56
|
expect(init.method).toBe('GET');
|
|
51
57
|
});
|
|
52
58
|
|
|
53
|
-
it('getBet sends GET with ID', async () => {
|
|
59
|
+
it('getBet sends GET with ID and unwraps data', async () => {
|
|
54
60
|
const bet = createBetFixture({ id: 'bet-123' });
|
|
55
|
-
mockFetch.mockResolvedValue(mockJsonResponse(bet));
|
|
61
|
+
mockFetch.mockResolvedValue(mockJsonResponse(wrapResponse(bet)));
|
|
56
62
|
|
|
57
63
|
const result = await client.getBet('bet-123');
|
|
58
64
|
|
|
@@ -62,9 +68,9 @@ describe('Bets endpoints', () => {
|
|
|
62
68
|
expect(init.method).toBe('GET');
|
|
63
69
|
});
|
|
64
70
|
|
|
65
|
-
it('createBet sends POST with body', async () => {
|
|
71
|
+
it('createBet sends POST with body and unwraps data', async () => {
|
|
66
72
|
const newBet = createBetFixture();
|
|
67
|
-
mockFetch.mockResolvedValue(mockJsonResponse(newBet));
|
|
73
|
+
mockFetch.mockResolvedValue(mockJsonResponse(wrapResponse(newBet)));
|
|
68
74
|
|
|
69
75
|
const params = {
|
|
70
76
|
question: 'Will it rain tomorrow?',
|
|
@@ -15,12 +15,16 @@ describe('Leaderboard endpoints', () => {
|
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it('getLeaderboard sends correct GET', async () => {
|
|
18
|
+
it('getLeaderboard sends correct GET and unwraps leaderboard array', async () => {
|
|
19
19
|
const entries = [
|
|
20
20
|
{ userId: 1, uuid: 'u1', displayName: 'User1', rank: 1, points: 1000 },
|
|
21
21
|
{ userId: 2, uuid: 'u2', displayName: 'User2', rank: 2, points: 800 },
|
|
22
22
|
];
|
|
23
|
-
|
|
23
|
+
// API returns { leaderboard: [...], pagination: {...} }
|
|
24
|
+
mockFetch.mockResolvedValue(mockJsonResponse({
|
|
25
|
+
leaderboard: entries,
|
|
26
|
+
pagination: { total: 2, page: 1, limit: 50 },
|
|
27
|
+
}));
|
|
24
28
|
|
|
25
29
|
const result = await client.getLeaderboard();
|
|
26
30
|
|
|
@@ -15,12 +15,13 @@ describe('Social endpoints', () => {
|
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it('getFriends sends correct GET', async () => {
|
|
18
|
+
it('getFriends sends correct GET and unwraps friends array', async () => {
|
|
19
19
|
const friends = [
|
|
20
|
-
{ id: 1, uuid: 'f1', displayName: 'Friend1' },
|
|
21
|
-
{ id: 2, uuid: 'f2', displayName: 'Friend2' },
|
|
20
|
+
{ id: 1, uuid: 'f1', displayName: 'Friend1', profileImageUrl: null },
|
|
21
|
+
{ id: 2, uuid: 'f2', displayName: 'Friend2', profileImageUrl: null },
|
|
22
22
|
];
|
|
23
|
-
|
|
23
|
+
// API returns { friends: [...], totalCount, error }
|
|
24
|
+
mockFetch.mockResolvedValue(mockJsonResponse({ friends, totalCount: 2, error: null }));
|
|
24
25
|
|
|
25
26
|
const result = await client.getFriends();
|
|
26
27
|
|
|
@@ -30,7 +31,7 @@ describe('Social endpoints', () => {
|
|
|
30
31
|
expect(init.method).toBe('GET');
|
|
31
32
|
});
|
|
32
33
|
|
|
33
|
-
it('sendFriendRequest sends POST', async () => {
|
|
34
|
+
it('sendFriendRequest sends POST with targetUserUuid', async () => {
|
|
34
35
|
mockFetch.mockResolvedValue(mockJsonResponse({ success: true }));
|
|
35
36
|
|
|
36
37
|
await client.sendFriendRequest('target-uuid');
|
|
@@ -38,7 +39,7 @@ describe('Social endpoints', () => {
|
|
|
38
39
|
const [url, init] = mockFetch.mock.calls[0];
|
|
39
40
|
expect(url).toBe('https://api.poll.fun/api/user/friends/request');
|
|
40
41
|
expect(init.method).toBe('POST');
|
|
41
|
-
expect(JSON.parse(init.body)).toEqual({
|
|
42
|
+
expect(JSON.parse(init.body)).toEqual({ targetUserUuid: 'target-uuid' });
|
|
42
43
|
});
|
|
43
44
|
|
|
44
45
|
it('favouriteBet sends POST', async () => {
|
|
@@ -16,36 +16,41 @@ describe('User endpoints', () => {
|
|
|
16
16
|
});
|
|
17
17
|
});
|
|
18
18
|
|
|
19
|
-
it('getAccount sends correct GET', async () => {
|
|
19
|
+
it('getAccount sends correct GET and unwraps user + address', async () => {
|
|
20
20
|
const user = createUserFixture();
|
|
21
|
-
|
|
21
|
+
const address = 'So1anaAddr3ss123';
|
|
22
|
+
// API returns { user: {...}, address: string, error: null }
|
|
23
|
+
mockFetch.mockResolvedValue(mockJsonResponse({ user, address, error: null }));
|
|
22
24
|
|
|
23
25
|
const result = await client.getAccount();
|
|
24
26
|
|
|
25
|
-
expect(result).toEqual(user);
|
|
27
|
+
expect(result).toEqual({ ...user, walletAddress: address });
|
|
26
28
|
const [url, init] = mockFetch.mock.calls[0];
|
|
27
29
|
expect(url).toBe('https://api.poll.fun/api/user/account');
|
|
28
30
|
expect(init.method).toBe('GET');
|
|
29
31
|
});
|
|
30
32
|
|
|
31
|
-
it('getProfile without uuid', async () => {
|
|
32
|
-
const profile = {
|
|
33
|
-
|
|
33
|
+
it('getProfile without uuid unwraps profile + stats', async () => {
|
|
34
|
+
const profile = { uuid: 'abc', displayName: 'Test', profileImageUrl: null };
|
|
35
|
+
const stats = { betsCreated: 5, totalWagered: 100 };
|
|
36
|
+
// API returns { profile: {...}, stats: {...}, error: null }
|
|
37
|
+
mockFetch.mockResolvedValue(mockJsonResponse({ profile, stats, error: null }));
|
|
34
38
|
|
|
35
39
|
const result = await client.getProfile();
|
|
36
40
|
|
|
37
|
-
expect(result).toEqual(profile);
|
|
41
|
+
expect(result).toEqual({ ...profile, stats });
|
|
38
42
|
const [url] = mockFetch.mock.calls[0];
|
|
39
43
|
expect(url).toBe('https://api.poll.fun/api/user/profile');
|
|
40
44
|
});
|
|
41
45
|
|
|
42
46
|
it('getProfile with uuid sends GET /api/user/profile/:uuid', async () => {
|
|
43
|
-
const profile = {
|
|
44
|
-
|
|
47
|
+
const profile = { uuid: 'user-uuid-123', displayName: 'OtherUser', profileImageUrl: null };
|
|
48
|
+
const stats = { betsCreated: 10 };
|
|
49
|
+
mockFetch.mockResolvedValue(mockJsonResponse({ profile, stats, error: null }));
|
|
45
50
|
|
|
46
51
|
const result = await client.getProfile('user-uuid-123');
|
|
47
52
|
|
|
48
|
-
expect(result).toEqual(profile);
|
|
53
|
+
expect(result).toEqual({ ...profile, stats });
|
|
49
54
|
const [url] = mockFetch.mock.calls[0];
|
|
50
55
|
expect(url).toBe('https://api.poll.fun/api/user/profile/user-uuid-123');
|
|
51
56
|
});
|
|
@@ -72,4 +77,16 @@ describe('User endpoints', () => {
|
|
|
72
77
|
expect(url).toBe('https://api.poll.fun/api/user/balance');
|
|
73
78
|
expect(init.method).toBe('GET');
|
|
74
79
|
});
|
|
80
|
+
|
|
81
|
+
it('getUsdcBalance sends correct GET and maps balance to usdc', async () => {
|
|
82
|
+
// API returns { balance: number, error: null }
|
|
83
|
+
mockFetch.mockResolvedValue(mockJsonResponse({ balance: 250.5, error: null }));
|
|
84
|
+
|
|
85
|
+
const result = await client.getUsdcBalance();
|
|
86
|
+
|
|
87
|
+
expect(result).toEqual({ usdc: 250.5, error: null });
|
|
88
|
+
const [url, init] = mockFetch.mock.calls[0];
|
|
89
|
+
expect(url).toBe('https://api.poll.fun/api/user/usdc/balance');
|
|
90
|
+
expect(init.method).toBe('GET');
|
|
91
|
+
});
|
|
75
92
|
});
|
|
@@ -15,7 +15,7 @@ describe('Wallet endpoints', () => {
|
|
|
15
15
|
});
|
|
16
16
|
});
|
|
17
17
|
|
|
18
|
-
it('getWalletTransactions sends correct GET', async () => {
|
|
18
|
+
it('getWalletTransactions sends correct GET and unwraps transactions', async () => {
|
|
19
19
|
const txns = [
|
|
20
20
|
{
|
|
21
21
|
signature: 'sig123',
|
|
@@ -30,7 +30,8 @@ describe('Wallet endpoints', () => {
|
|
|
30
30
|
createdAt: '2026-01-02T00:00:00.000Z',
|
|
31
31
|
},
|
|
32
32
|
];
|
|
33
|
-
|
|
33
|
+
// API returns { transactions: [...], error: null }
|
|
34
|
+
mockFetch.mockResolvedValue(mockJsonResponse({ transactions: txns, error: null }));
|
|
34
35
|
|
|
35
36
|
const result = await client.getWalletTransactions();
|
|
36
37
|
|