@metamask/social-controllers 0.1.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 (60) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/LICENSE +20 -0
  3. package/README.md +15 -0
  4. package/dist/SocialController-method-action-types.cjs +7 -0
  5. package/dist/SocialController-method-action-types.cjs.map +1 -0
  6. package/dist/SocialController-method-action-types.d.cts +56 -0
  7. package/dist/SocialController-method-action-types.d.cts.map +1 -0
  8. package/dist/SocialController-method-action-types.d.mts +56 -0
  9. package/dist/SocialController-method-action-types.d.mts.map +1 -0
  10. package/dist/SocialController-method-action-types.mjs +6 -0
  11. package/dist/SocialController-method-action-types.mjs.map +1 -0
  12. package/dist/SocialController.cjs +129 -0
  13. package/dist/SocialController.cjs.map +1 -0
  14. package/dist/SocialController.d.cts +71 -0
  15. package/dist/SocialController.d.cts.map +1 -0
  16. package/dist/SocialController.d.mts +71 -0
  17. package/dist/SocialController.d.mts.map +1 -0
  18. package/dist/SocialController.mjs +124 -0
  19. package/dist/SocialController.mjs.map +1 -0
  20. package/dist/SocialService-method-action-types.cjs +7 -0
  21. package/dist/SocialService-method-action-types.cjs.map +1 -0
  22. package/dist/SocialService-method-action-types.d.cts +125 -0
  23. package/dist/SocialService-method-action-types.d.cts.map +1 -0
  24. package/dist/SocialService-method-action-types.d.mts +125 -0
  25. package/dist/SocialService-method-action-types.d.mts.map +1 -0
  26. package/dist/SocialService-method-action-types.mjs +6 -0
  27. package/dist/SocialService-method-action-types.mjs.map +1 -0
  28. package/dist/SocialService.cjs +434 -0
  29. package/dist/SocialService.cjs.map +1 -0
  30. package/dist/SocialService.d.cts +113 -0
  31. package/dist/SocialService.d.cts.map +1 -0
  32. package/dist/SocialService.d.mts +113 -0
  33. package/dist/SocialService.d.mts.map +1 -0
  34. package/dist/SocialService.mjs +430 -0
  35. package/dist/SocialService.mjs.map +1 -0
  36. package/dist/index.cjs +12 -0
  37. package/dist/index.cjs.map +1 -0
  38. package/dist/index.d.cts +9 -0
  39. package/dist/index.d.cts.map +1 -0
  40. package/dist/index.d.mts +9 -0
  41. package/dist/index.d.mts.map +1 -0
  42. package/dist/index.mjs +4 -0
  43. package/dist/index.mjs.map +1 -0
  44. package/dist/social-constants.cjs +24 -0
  45. package/dist/social-constants.cjs.map +1 -0
  46. package/dist/social-constants.d.cts +21 -0
  47. package/dist/social-constants.d.cts.map +1 -0
  48. package/dist/social-constants.d.mts +21 -0
  49. package/dist/social-constants.d.mts.map +1 -0
  50. package/dist/social-constants.mjs +21 -0
  51. package/dist/social-constants.mjs.map +1 -0
  52. package/dist/social-types.cjs +6 -0
  53. package/dist/social-types.cjs.map +1 -0
  54. package/dist/social-types.d.cts +212 -0
  55. package/dist/social-types.d.cts.map +1 -0
  56. package/dist/social-types.d.mts +212 -0
  57. package/dist/social-types.d.mts.map +1 -0
  58. package/dist/social-types.mjs +5 -0
  59. package/dist/social-types.mjs.map +1 -0
  60. package/package.json +75 -0
@@ -0,0 +1,434 @@
1
+ "use strict";
2
+ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
3
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
4
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
5
+ return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
6
+ };
7
+ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
8
+ if (kind === "m") throw new TypeError("Private method is not writable");
9
+ if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
10
+ if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
11
+ return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
+ };
13
+ var _SocialService_instances, _a, _SocialService_baseUrl, _SocialService_v1Url_get, _SocialService_v2Url_get, _SocialService_throwIfNotOk, _SocialService_fetchPositions;
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.SocialService = void 0;
16
+ const base_data_service_1 = require("@metamask/base-data-service");
17
+ const controller_utils_1 = require("@metamask/controller-utils");
18
+ const superstruct_1 = require("@metamask/superstruct");
19
+ const social_constants_1 = require("./social-constants.cjs");
20
+ // ---------------------------------------------------------------------------
21
+ // Superstruct validation schemas
22
+ // ---------------------------------------------------------------------------
23
+ const SocialHandlesStruct = (0, superstruct_1.type)({
24
+ twitter: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
25
+ farcaster: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
26
+ ens: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
27
+ lens: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
28
+ });
29
+ const ProfileSummaryStruct = (0, superstruct_1.type)({
30
+ profileId: (0, superstruct_1.string)(),
31
+ address: (0, superstruct_1.string)(),
32
+ name: (0, superstruct_1.string)(),
33
+ imageUrl: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
34
+ });
35
+ const TradeStruct = (0, superstruct_1.type)({
36
+ direction: (0, superstruct_1.string)(),
37
+ tokenAmount: (0, superstruct_1.number)(),
38
+ usdCost: (0, superstruct_1.number)(),
39
+ timestamp: (0, superstruct_1.number)(),
40
+ transactionHash: (0, superstruct_1.string)(),
41
+ });
42
+ const PositionStruct = (0, superstruct_1.type)({
43
+ tokenSymbol: (0, superstruct_1.string)(),
44
+ tokenName: (0, superstruct_1.string)(),
45
+ tokenAddress: (0, superstruct_1.string)(),
46
+ chain: (0, superstruct_1.string)(),
47
+ positionAmount: (0, superstruct_1.number)(),
48
+ boughtUsd: (0, superstruct_1.number)(),
49
+ soldUsd: (0, superstruct_1.number)(),
50
+ realizedPnl: (0, superstruct_1.number)(),
51
+ costBasis: (0, superstruct_1.number)(),
52
+ trades: (0, superstruct_1.array)(TradeStruct),
53
+ lastTradeAt: (0, superstruct_1.number)(),
54
+ currentValueUSD: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
55
+ pnlValueUsd: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
56
+ pnlPercent: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
57
+ });
58
+ const PaginationStruct = (0, superstruct_1.type)({
59
+ hasMore: (0, superstruct_1.boolean)(),
60
+ nextPage: (0, superstruct_1.optional)((0, superstruct_1.number)()),
61
+ });
62
+ const LeaderboardEntryStruct = (0, superstruct_1.type)({
63
+ rank: (0, superstruct_1.number)(),
64
+ addresses: (0, superstruct_1.array)((0, superstruct_1.string)()),
65
+ profileId: (0, superstruct_1.string)(),
66
+ name: (0, superstruct_1.string)(),
67
+ imageUrl: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
68
+ pnl30d: (0, superstruct_1.number)(),
69
+ winRate30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
70
+ roiPercent30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
71
+ tradeCount30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
72
+ pnl7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
73
+ winRate7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
74
+ roiPercent7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
75
+ tradeCount7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
76
+ pnlPerChain: (0, superstruct_1.record)((0, superstruct_1.string)(), (0, superstruct_1.number)()),
77
+ followerCount: (0, superstruct_1.number)(),
78
+ socialHandles: SocialHandlesStruct,
79
+ });
80
+ const LeaderboardResponseStruct = (0, superstruct_1.type)({
81
+ traders: (0, superstruct_1.array)(LeaderboardEntryStruct),
82
+ });
83
+ const TraderProfileStruct = (0, superstruct_1.type)({
84
+ profileId: (0, superstruct_1.string)(),
85
+ address: (0, superstruct_1.string)(),
86
+ allAddresses: (0, superstruct_1.array)((0, superstruct_1.string)()),
87
+ name: (0, superstruct_1.string)(),
88
+ imageUrl: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
89
+ });
90
+ const TraderStatsStruct = (0, superstruct_1.type)({
91
+ pnl30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
92
+ winRate30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
93
+ roiPercent30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
94
+ tradeCount30d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
95
+ pnl7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
96
+ winRate7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
97
+ roiPercent7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
98
+ tradeCount7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
99
+ });
100
+ const PerChainBreakdownStruct = (0, superstruct_1.type)({
101
+ perChainPnl: (0, superstruct_1.record)((0, superstruct_1.string)(), (0, superstruct_1.number)()),
102
+ perChainRoi: (0, superstruct_1.record)((0, superstruct_1.string)(), (0, superstruct_1.nullable)((0, superstruct_1.number)())),
103
+ perChainVolume: (0, superstruct_1.record)((0, superstruct_1.string)(), (0, superstruct_1.number)()),
104
+ });
105
+ const TraderProfileResponseStruct = (0, superstruct_1.type)({
106
+ profile: TraderProfileStruct,
107
+ stats: TraderStatsStruct,
108
+ perChainBreakdown: PerChainBreakdownStruct,
109
+ socialHandles: SocialHandlesStruct,
110
+ followerCount: (0, superstruct_1.number)(),
111
+ followingCount: (0, superstruct_1.number)(),
112
+ });
113
+ const PositionsResponseStruct = (0, superstruct_1.type)({
114
+ positions: (0, superstruct_1.array)(PositionStruct),
115
+ pagination: PaginationStruct,
116
+ computedAt: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
117
+ });
118
+ const FollowersResponseStruct = (0, superstruct_1.type)({
119
+ followers: (0, superstruct_1.array)(ProfileSummaryStruct),
120
+ count: (0, superstruct_1.number)(),
121
+ });
122
+ const FollowingResponseStruct = (0, superstruct_1.type)({
123
+ following: (0, superstruct_1.array)(ProfileSummaryStruct),
124
+ count: (0, superstruct_1.number)(),
125
+ });
126
+ const FollowResponseStruct = (0, superstruct_1.type)({
127
+ followed: (0, superstruct_1.array)(ProfileSummaryStruct),
128
+ });
129
+ const UnfollowResponseStruct = (0, superstruct_1.type)({
130
+ unfollowed: (0, superstruct_1.array)(ProfileSummaryStruct),
131
+ });
132
+ // ---------------------------------------------------------------------------
133
+ // Messenger types
134
+ // ---------------------------------------------------------------------------
135
+ const MESSENGER_EXPOSED_METHODS = [
136
+ 'fetchLeaderboard',
137
+ 'fetchTraderProfile',
138
+ 'fetchOpenPositions',
139
+ 'fetchClosedPositions',
140
+ 'fetchFollowers',
141
+ 'fetchFollowing',
142
+ 'follow',
143
+ 'unfollow',
144
+ ];
145
+ // ---------------------------------------------------------------------------
146
+ // Service
147
+ // ---------------------------------------------------------------------------
148
+ /**
149
+ * Data service wrapping social-api endpoints.
150
+ */
151
+ class SocialService extends base_data_service_1.BaseDataService {
152
+ constructor({ messenger, baseUrl, policyOptions, }) {
153
+ super({ name: social_constants_1.serviceName, messenger, policyOptions });
154
+ _SocialService_instances.add(this);
155
+ _SocialService_baseUrl.set(this, void 0);
156
+ __classPrivateFieldSet(this, _SocialService_baseUrl, baseUrl, "f");
157
+ this.messenger.registerMethodActionHandlers(this, MESSENGER_EXPOSED_METHODS);
158
+ }
159
+ /**
160
+ * Fetches the leaderboard of top traders.
161
+ *
162
+ * Calls `GET ${baseUrl}/leaderboard`.
163
+ *
164
+ * @param options - Optional query parameters for sorting, chain filtering, and limit.
165
+ * @returns The leaderboard response with ranked traders.
166
+ */
167
+ async fetchLeaderboard(options) {
168
+ const leaderboardResponse = await this.fetchQuery({
169
+ queryKey: [`${this.name}:fetchLeaderboard`, options ?? null],
170
+ queryFn: async () => {
171
+ const { sort, chains, limit } = options ?? {};
172
+ const url = new URL(`${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/leaderboard`);
173
+ if (sort) {
174
+ url.searchParams.append('sort', sort);
175
+ }
176
+ if (chains) {
177
+ for (const chain of chains) {
178
+ url.searchParams.append('chains', chain);
179
+ }
180
+ }
181
+ if (limit !== undefined) {
182
+ url.searchParams.append('limit', String(limit));
183
+ }
184
+ const response = await fetch(url.toString());
185
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_LEADERBOARD_FAILED);
186
+ const leaderboardData = await response.json();
187
+ if (!(0, superstruct_1.is)(leaderboardData, LeaderboardResponseStruct)) {
188
+ throw new Error(social_constants_1.SocialServiceErrorMessage.FETCH_LEADERBOARD_INVALID_RESPONSE);
189
+ }
190
+ return leaderboardData;
191
+ },
192
+ });
193
+ return leaderboardResponse;
194
+ }
195
+ /**
196
+ * Fetches a trader's profile by address or profile ID.
197
+ *
198
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.
199
+ *
200
+ * @param options - Options bag.
201
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
202
+ * @returns The trader profile response.
203
+ */
204
+ async fetchTraderProfile(options) {
205
+ const { addressOrId } = options;
206
+ const traderProfileResponse = await this.fetchQuery({
207
+ queryKey: [`${this.name}:fetchTraderProfile`, addressOrId],
208
+ queryFn: async () => {
209
+ const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/traders/${encodeURIComponent(addressOrId)}/profile`;
210
+ const response = await fetch(url);
211
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_TRADER_PROFILE_FAILED);
212
+ const traderProfileData = await response.json();
213
+ if (!(0, superstruct_1.is)(traderProfileData, TraderProfileResponseStruct)) {
214
+ throw new Error(social_constants_1.SocialServiceErrorMessage.FETCH_TRADER_PROFILE_INVALID_RESPONSE);
215
+ }
216
+ return traderProfileData;
217
+ },
218
+ });
219
+ return traderProfileResponse;
220
+ }
221
+ /**
222
+ * Fetches a trader's open positions.
223
+ *
224
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/positions/open`.
225
+ *
226
+ * @param options - Options bag.
227
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
228
+ * @param options.chain - Filter by chain.
229
+ * @param options.sort - Sort by 'value' or 'latest'.
230
+ * @param options.limit - Number of results per page.
231
+ * @param options.page - Page number (1-based).
232
+ * @returns The positions response.
233
+ */
234
+ async fetchOpenPositions(options) {
235
+ return __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_fetchPositions).call(this, 'open', options);
236
+ }
237
+ /**
238
+ * Fetches a trader's closed positions.
239
+ *
240
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/positions/closed`.
241
+ *
242
+ * @param options - Options bag.
243
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
244
+ * @param options.chain - Filter by chain.
245
+ * @param options.sort - Sort by 'value' or 'latest'.
246
+ * @param options.limit - Number of results per page.
247
+ * @param options.page - Page number (1-based).
248
+ * @returns The positions response.
249
+ */
250
+ async fetchClosedPositions(options) {
251
+ return __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_fetchPositions).call(this, 'closed', options);
252
+ }
253
+ /**
254
+ * Fetches a trader's MetaMask followers.
255
+ *
256
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/followers`.
257
+ *
258
+ * @param options - Options bag.
259
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
260
+ * @returns The followers response.
261
+ */
262
+ async fetchFollowers(options) {
263
+ const { addressOrId } = options;
264
+ const followersResponse = await this.fetchQuery({
265
+ queryKey: [`${this.name}:fetchFollowers`, addressOrId],
266
+ queryFn: async () => {
267
+ const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/traders/${encodeURIComponent(addressOrId)}/followers`;
268
+ const response = await fetch(url);
269
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_FOLLOWERS_FAILED);
270
+ const followersData = await response.json();
271
+ if (!(0, superstruct_1.is)(followersData, FollowersResponseStruct)) {
272
+ throw new Error(social_constants_1.SocialServiceErrorMessage.FETCH_FOLLOWERS_INVALID_RESPONSE);
273
+ }
274
+ return followersData;
275
+ },
276
+ });
277
+ return followersResponse;
278
+ }
279
+ /**
280
+ * Fetches the list of traders a user is following.
281
+ *
282
+ * Calls `GET ${baseUrl}/users/${addressOrUid}/following`.
283
+ *
284
+ * @param options - Options bag.
285
+ * @param options.addressOrUid - Wallet address or Clicker profile ID.
286
+ * @returns The following response.
287
+ */
288
+ async fetchFollowing(options) {
289
+ const { addressOrUid } = options;
290
+ const followingResponse = await this.fetchQuery({
291
+ queryKey: [`${this.name}:fetchFollowing`, addressOrUid],
292
+ staleTime: 0,
293
+ queryFn: async () => {
294
+ const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/users/${encodeURIComponent(addressOrUid)}/following`;
295
+ const response = await fetch(url);
296
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_FOLLOWING_FAILED);
297
+ const followingData = await response.json();
298
+ if (!(0, superstruct_1.is)(followingData, FollowingResponseStruct)) {
299
+ throw new Error(social_constants_1.SocialServiceErrorMessage.FETCH_FOLLOWING_INVALID_RESPONSE);
300
+ }
301
+ return followingData;
302
+ },
303
+ });
304
+ return followingResponse;
305
+ }
306
+ /**
307
+ * Follows one or more traders.
308
+ *
309
+ * Calls `PUT ${baseUrl}/users/${addressOrUid}/follows`.
310
+ *
311
+ * @param options - Options bag.
312
+ * @param options.addressOrUid - Wallet address or Clicker profile ID of the user.
313
+ * @param options.targets - Array of wallet addresses or profile IDs to follow.
314
+ * @returns The follow response with confirmed follows.
315
+ */
316
+ async follow(options) {
317
+ const { addressOrUid, targets } = options;
318
+ const followResponse = await this.fetchQuery({
319
+ queryKey: [`${this.name}:follow`, addressOrUid, targets],
320
+ staleTime: 0,
321
+ queryFn: async () => {
322
+ const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/users/${encodeURIComponent(addressOrUid)}/follows`;
323
+ const response = await fetch(url, {
324
+ method: 'PUT',
325
+ headers: { 'Content-Type': 'application/json' },
326
+ body: JSON.stringify({ targets }),
327
+ });
328
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FOLLOW_FAILED);
329
+ const followData = await response.json();
330
+ if (!(0, superstruct_1.is)(followData, FollowResponseStruct)) {
331
+ throw new Error(social_constants_1.SocialServiceErrorMessage.FOLLOW_INVALID_RESPONSE);
332
+ }
333
+ return followData;
334
+ },
335
+ });
336
+ return followResponse;
337
+ }
338
+ /**
339
+ * Unfollows one or more traders.
340
+ *
341
+ * Calls `DELETE ${baseUrl}/users/${addressOrUid}/follows?targets=...`.
342
+ * Targets are sent as query params because Fastify does not parse
343
+ * request bodies on DELETE requests per RFC 9110.
344
+ *
345
+ * @param options - Options bag.
346
+ * @param options.addressOrUid - Wallet address or Clicker profile ID of the user.
347
+ * @param options.targets - Array of wallet addresses or profile IDs to unfollow.
348
+ * @returns The unfollow response with confirmed unfollows.
349
+ */
350
+ async unfollow(options) {
351
+ const { addressOrUid, targets } = options;
352
+ const unfollowResponse = await this.fetchQuery({
353
+ queryKey: [`${this.name}:unfollow`, addressOrUid, targets],
354
+ staleTime: 0,
355
+ queryFn: async () => {
356
+ const url = new URL(`${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/users/${encodeURIComponent(addressOrUid)}/follows`);
357
+ for (const target of targets) {
358
+ url.searchParams.append('targets', target);
359
+ }
360
+ const response = await fetch(url.toString(), { method: 'DELETE' });
361
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.UNFOLLOW_FAILED);
362
+ const unfollowData = await response.json();
363
+ if (!(0, superstruct_1.is)(unfollowData, UnfollowResponseStruct)) {
364
+ throw new Error(social_constants_1.SocialServiceErrorMessage.UNFOLLOW_INVALID_RESPONSE);
365
+ }
366
+ return unfollowData;
367
+ },
368
+ });
369
+ return unfollowResponse;
370
+ }
371
+ }
372
+ exports.SocialService = SocialService;
373
+ _a = SocialService, _SocialService_baseUrl = new WeakMap(), _SocialService_instances = new WeakSet(), _SocialService_v1Url_get = function _SocialService_v1Url_get() {
374
+ return `${__classPrivateFieldGet(this, _SocialService_baseUrl, "f")}/api/v1`;
375
+ }, _SocialService_v2Url_get = function _SocialService_v2Url_get() {
376
+ return `${__classPrivateFieldGet(this, _SocialService_baseUrl, "f")}/api/v2`;
377
+ }, _SocialService_throwIfNotOk = function _SocialService_throwIfNotOk(response, message) {
378
+ if (!response.ok) {
379
+ throw new controller_utils_1.HttpError(response.status, `${message}: ${response.status}`);
380
+ }
381
+ }, _SocialService_fetchPositions =
382
+ /**
383
+ * Shared helper for fetching open/closed positions.
384
+ *
385
+ * @param status - "open" or "closed".
386
+ * @param options - Options bag including addressOrId and query parameters.
387
+ * @returns The positions response.
388
+ */
389
+ async function _SocialService_fetchPositions(status, options) {
390
+ const { addressOrId, chain, sort, limit, page } = options;
391
+ const failedMessage = status === 'open'
392
+ ? social_constants_1.SocialServiceErrorMessage.FETCH_OPEN_POSITIONS_FAILED
393
+ : social_constants_1.SocialServiceErrorMessage.FETCH_CLOSED_POSITIONS_FAILED;
394
+ const invalidMessage = status === 'open'
395
+ ? social_constants_1.SocialServiceErrorMessage.FETCH_OPEN_POSITIONS_INVALID_RESPONSE
396
+ : social_constants_1.SocialServiceErrorMessage.FETCH_CLOSED_POSITIONS_INVALID_RESPONSE;
397
+ const positionsResponse = await this.fetchQuery({
398
+ queryKey: [
399
+ `${this.name}:fetch${status === 'open' ? 'Open' : 'Closed'}Positions`,
400
+ addressOrId,
401
+ chain ?? null,
402
+ // sort is not used for open positions (v2 endpoint dropped it),
403
+ // so exclude it from the key to avoid redundant cache entries
404
+ status === 'closed' ? (sort ?? null) : null,
405
+ limit ?? null,
406
+ page ?? null,
407
+ ],
408
+ queryFn: async () => {
409
+ const url = new URL(`${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v2Url_get)}/traders/${encodeURIComponent(addressOrId)}/positions/${status}`);
410
+ if (chain) {
411
+ url.searchParams.append('chain', chain);
412
+ }
413
+ // sort is not supported on the v2 open-positions endpoint
414
+ if (sort && status === 'closed') {
415
+ url.searchParams.append('sort', sort);
416
+ }
417
+ if (limit !== undefined) {
418
+ url.searchParams.append('limit', String(limit));
419
+ }
420
+ if (page !== undefined) {
421
+ url.searchParams.append('page', String(page));
422
+ }
423
+ const response = await fetch(url.toString());
424
+ __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, failedMessage);
425
+ const positionsData = await response.json();
426
+ if (!(0, superstruct_1.is)(positionsData, PositionsResponseStruct)) {
427
+ throw new Error(invalidMessage);
428
+ }
429
+ return positionsData;
430
+ },
431
+ });
432
+ return positionsResponse;
433
+ };
434
+ //# sourceMappingURL=SocialService.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocialService.cjs","sourceRoot":"","sources":["../src/SocialService.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;AAKA,mEAA8D;AAE9D,iEAAuD;AAEvD,uDAU+B;AAE/B,6DAA4E;AAmB5E,8EAA8E;AAC9E,iCAAiC;AACjC,8EAA8E;AAE9E,MAAM,mBAAmB,GAAG,IAAA,kBAAU,EAAC;IACrC,OAAO,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACrC,SAAS,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACvC,GAAG,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACjC,IAAI,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACnC,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,IAAA,kBAAU,EAAC;IACtC,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,OAAO,EAAE,IAAA,oBAAM,GAAE;IACjB,IAAI,EAAE,IAAA,oBAAM,GAAE;IACd,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,IAAA,kBAAU,EAAC;IAC7B,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,WAAW,EAAE,IAAA,oBAAM,GAAE;IACrB,OAAO,EAAE,IAAA,oBAAM,GAAE;IACjB,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,eAAe,EAAE,IAAA,oBAAM,GAAE;CAC1B,CAAC,CAAC;AAEH,MAAM,cAAc,GAAG,IAAA,kBAAU,EAAC;IAChC,WAAW,EAAE,IAAA,oBAAM,GAAE;IACrB,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,YAAY,EAAE,IAAA,oBAAM,GAAE;IACtB,KAAK,EAAE,IAAA,oBAAM,GAAE;IACf,cAAc,EAAE,IAAA,oBAAM,GAAE;IACxB,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,OAAO,EAAE,IAAA,oBAAM,GAAE;IACjB,WAAW,EAAE,IAAA,oBAAM,GAAE;IACrB,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,MAAM,EAAE,IAAA,mBAAK,EAAC,WAAW,CAAC;IAC1B,WAAW,EAAE,IAAA,oBAAM,GAAE;IACrB,eAAe,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC7C,WAAW,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACzC,UAAU,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACzC,CAAC,CAAC;AAEH,MAAM,gBAAgB,GAAG,IAAA,kBAAU,EAAC;IAClC,OAAO,EAAE,IAAA,qBAAO,GAAE;IAClB,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC;CAC7B,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,IAAA,kBAAU,EAAC;IACxC,IAAI,EAAE,IAAA,oBAAM,GAAE;IACd,SAAS,EAAE,IAAA,mBAAK,EAAC,IAAA,oBAAM,GAAE,CAAC;IAC1B,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,IAAI,EAAE,IAAA,oBAAM,GAAE;IACd,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACtC,MAAM,EAAE,IAAA,oBAAM,GAAE;IAChB,UAAU,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACxC,aAAa,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC3C,aAAa,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC3C,KAAK,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACnC,SAAS,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACvC,YAAY,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC1C,WAAW,EAAE,IAAA,oBAAM,EAAC,IAAA,oBAAM,GAAE,EAAE,IAAA,oBAAM,GAAE,CAAC;IACvC,aAAa,EAAE,IAAA,oBAAM,GAAE;IACvB,aAAa,EAAE,mBAAmB;CACnC,CAAC,CAAC;AAEH,MAAM,yBAAyB,GAAG,IAAA,kBAAU,EAAC;IAC3C,OAAO,EAAE,IAAA,mBAAK,EAAC,sBAAsB,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,mBAAmB,GAAG,IAAA,kBAAU,EAAC;IACrC,SAAS,EAAE,IAAA,oBAAM,GAAE;IACnB,OAAO,EAAE,IAAA,oBAAM,GAAE;IACjB,YAAY,EAAE,IAAA,mBAAK,EAAC,IAAA,oBAAM,GAAE,CAAC;IAC7B,IAAI,EAAE,IAAA,oBAAM,GAAE;IACd,QAAQ,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,iBAAiB,GAAG,IAAA,kBAAU,EAAC;IACnC,MAAM,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACpC,UAAU,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACxC,aAAa,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC3C,aAAa,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC3C,KAAK,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACnC,SAAS,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACvC,YAAY,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IAC1C,YAAY,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,uBAAuB,GAAG,IAAA,kBAAU,EAAC;IACzC,WAAW,EAAE,IAAA,oBAAM,EAAC,IAAA,oBAAM,GAAE,EAAE,IAAA,oBAAM,GAAE,CAAC;IACvC,WAAW,EAAE,IAAA,oBAAM,EAAC,IAAA,oBAAM,GAAE,EAAE,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;IACjD,cAAc,EAAE,IAAA,oBAAM,EAAC,IAAA,oBAAM,GAAE,EAAE,IAAA,oBAAM,GAAE,CAAC;CAC3C,CAAC,CAAC;AAEH,MAAM,2BAA2B,GAAG,IAAA,kBAAU,EAAC;IAC7C,OAAO,EAAE,mBAAmB;IAC5B,KAAK,EAAE,iBAAiB;IACxB,iBAAiB,EAAE,uBAAuB;IAC1C,aAAa,EAAE,mBAAmB;IAClC,aAAa,EAAE,IAAA,oBAAM,GAAE;IACvB,cAAc,EAAE,IAAA,oBAAM,GAAE;CACzB,CAAC,CAAC;AAEH,MAAM,uBAAuB,GAAG,IAAA,kBAAU,EAAC;IACzC,SAAS,EAAE,IAAA,mBAAK,EAAC,cAAc,CAAC;IAChC,UAAU,EAAE,gBAAgB;IAC5B,UAAU,EAAE,IAAA,sBAAQ,EAAC,IAAA,sBAAQ,EAAC,IAAA,oBAAM,GAAE,CAAC,CAAC;CACzC,CAAC,CAAC;AAEH,MAAM,uBAAuB,GAAG,IAAA,kBAAU,EAAC;IACzC,SAAS,EAAE,IAAA,mBAAK,EAAC,oBAAoB,CAAC;IACtC,KAAK,EAAE,IAAA,oBAAM,GAAE;CAChB,CAAC,CAAC;AAEH,MAAM,uBAAuB,GAAG,IAAA,kBAAU,EAAC;IACzC,SAAS,EAAE,IAAA,mBAAK,EAAC,oBAAoB,CAAC;IACtC,KAAK,EAAE,IAAA,oBAAM,GAAE;CAChB,CAAC,CAAC;AAEH,MAAM,oBAAoB,GAAG,IAAA,kBAAU,EAAC;IACtC,QAAQ,EAAE,IAAA,mBAAK,EAAC,oBAAoB,CAAC;CACtC,CAAC,CAAC;AAEH,MAAM,sBAAsB,GAAG,IAAA,kBAAU,EAAC;IACxC,UAAU,EAAE,IAAA,mBAAK,EAAC,oBAAoB,CAAC;CACxC,CAAC,CAAC;AAEH,8EAA8E;AAC9E,kBAAkB;AAClB,8EAA8E;AAE9E,MAAM,yBAAyB,GAAG;IAChC,kBAAkB;IAClB,oBAAoB;IACpB,oBAAoB;IACpB,sBAAsB;IACtB,gBAAgB;IAChB,gBAAgB;IAChB,QAAQ;IACR,UAAU;CACF,CAAC;AAgBX,8EAA8E;AAC9E,UAAU;AACV,8EAA8E;AAE9E;;GAEG;AACH,MAAa,aAAc,SAAQ,mCAGlC;IAWC,YAAY,EACV,SAAS,EACT,OAAO,EACP,aAAa,GAKd;QACC,KAAK,CAAC,EAAE,IAAI,EAAE,8BAAW,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;;QAnBhD,yCAAiB;QAoBxB,uBAAA,IAAI,0BAAY,OAAO,MAAA,CAAC;QAExB,IAAI,CAAC,SAAS,CAAC,4BAA4B,CACzC,IAAI,EACJ,yBAAyB,CAC1B,CAAC;IACJ,CAAC;IAcD;;;;;;;OAOG;IACH,KAAK,CAAC,gBAAgB,CACpB,OAAiC;QAEjC,MAAM,mBAAmB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAChD,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,mBAAmB,EAAE,OAAO,IAAI,IAAI,CAAC;YAC5D,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,OAAO,IAAI,EAAE,CAAC;gBAC9C,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,GAAG,uBAAA,IAAI,0DAAO,cAAc,CAAC,CAAC;gBAClD,IAAI,IAAI,EAAE,CAAC;oBACT,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;gBACxC,CAAC;gBACD,IAAI,MAAM,EAAE,CAAC;oBACX,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;wBAC3B,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;oBAC3C,CAAC;gBACH,CAAC;gBACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;oBACxB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;gBAClD,CAAC;gBAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;gBAC7C,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EACX,QAAQ,EACR,4CAAyB,CAAC,wBAAwB,CACnD,CAAC;gBACF,MAAM,eAAe,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC9C,IAAI,CAAC,IAAA,gBAAE,EAAC,eAAe,EAAE,yBAAyB,CAAC,EAAE,CAAC;oBACpD,MAAM,IAAI,KAAK,CACb,4CAAyB,CAAC,kCAAkC,CAC7D,CAAC;gBACJ,CAAC;gBACD,OAAO,eAAsC,CAAC;YAChD,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,mBAAmB,CAAC;IAC7B,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,kBAAkB,CACtB,OAAkC;QAElC,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QAEhC,MAAM,qBAAqB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAClD,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,qBAAqB,EAAE,WAAW,CAAC;YAC1D,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,GAAG,GAAG,GAAG,uBAAA,IAAI,0DAAO,YAAY,kBAAkB,CAAC,WAAW,CAAC,UAAU,CAAC;gBAChF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClC,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EACX,QAAQ,EACR,4CAAyB,CAAC,2BAA2B,CACtD,CAAC;gBACF,MAAM,iBAAiB,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAChD,IAAI,CAAC,IAAA,gBAAE,EAAC,iBAAiB,EAAE,2BAA2B,CAAC,EAAE,CAAC;oBACxD,MAAM,IAAI,KAAK,CACb,4CAAyB,CAAC,qCAAqC,CAChE,CAAC;gBACJ,CAAC;gBACD,OAAO,iBAA0C,CAAC;YACpD,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,qBAAqB,CAAC;IAC/B,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,kBAAkB,CACtB,OAA8B;QAE9B,OAAO,uBAAA,IAAI,+DAAgB,MAApB,IAAI,EAAiB,MAAM,EAAE,OAAO,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;;;;;;;;OAYG;IACH,KAAK,CAAC,oBAAoB,CACxB,OAA8B;QAE9B,OAAO,uBAAA,IAAI,+DAAgB,MAApB,IAAI,EAAiB,QAAQ,EAAE,OAAO,CAAC,CAAC;IACjD,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,cAAc,CAClB,OAA8B;QAE9B,MAAM,EAAE,WAAW,EAAE,GAAG,OAAO,CAAC;QAEhC,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAC9C,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,iBAAiB,EAAE,WAAW,CAAC;YACtD,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,GAAG,GAAG,GAAG,uBAAA,IAAI,0DAAO,YAAY,kBAAkB,CAAC,WAAW,CAAC,YAAY,CAAC;gBAClF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClC,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EACX,QAAQ,EACR,4CAAyB,CAAC,sBAAsB,CACjD,CAAC;gBACF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,CAAC,IAAA,gBAAE,EAAC,aAAa,EAAE,uBAAuB,CAAC,EAAE,CAAC;oBAChD,MAAM,IAAI,KAAK,CACb,4CAAyB,CAAC,gCAAgC,CAC3D,CAAC;gBACJ,CAAC;gBACD,OAAO,aAAkC,CAAC;YAC5C,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED;;;;;;;;OAQG;IACH,KAAK,CAAC,cAAc,CAClB,OAA8B;QAE9B,MAAM,EAAE,YAAY,EAAE,GAAG,OAAO,CAAC;QAEjC,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAC9C,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,iBAAiB,EAAE,YAAY,CAAC;YACvD,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,GAAG,GAAG,GAAG,uBAAA,IAAI,0DAAO,UAAU,kBAAkB,CAAC,YAAY,CAAC,YAAY,CAAC;gBACjF,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;gBAClC,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EACX,QAAQ,EACR,4CAAyB,CAAC,sBAAsB,CACjD,CAAC;gBACF,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC5C,IAAI,CAAC,IAAA,gBAAE,EAAC,aAAa,EAAE,uBAAuB,CAAC,EAAE,CAAC;oBAChD,MAAM,IAAI,KAAK,CACb,4CAAyB,CAAC,gCAAgC,CAC3D,CAAC;gBACJ,CAAC;gBACD,OAAO,aAAkC,CAAC;YAC5C,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,iBAAiB,CAAC;IAC3B,CAAC;IAED;;;;;;;;;OASG;IACH,KAAK,CAAC,MAAM,CAAC,OAAsB;QACjC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAE1C,MAAM,cAAc,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAC3C,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,SAAS,EAAE,YAAY,EAAE,OAAO,CAAC;YACxD,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,GAAG,GAAG,GAAG,uBAAA,IAAI,0DAAO,UAAU,kBAAkB,CAAC,YAAY,CAAC,UAAU,CAAC;gBAC/E,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,EAAE;oBAChC,MAAM,EAAE,KAAK;oBACb,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;oBAC/C,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,CAAC;iBAClC,CAAC,CAAC;gBACH,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EACX,QAAQ,EACR,4CAAyB,CAAC,aAAa,CACxC,CAAC;gBACF,MAAM,UAAU,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBACzC,IAAI,CAAC,IAAA,gBAAE,EAAC,UAAU,EAAE,oBAAoB,CAAC,EAAE,CAAC;oBAC1C,MAAM,IAAI,KAAK,CAAC,4CAAyB,CAAC,uBAAuB,CAAC,CAAC;gBACrE,CAAC;gBACD,OAAO,UAA4B,CAAC;YACtC,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,cAAc,CAAC;IACxB,CAAC;IAED;;;;;;;;;;;OAWG;IACH,KAAK,CAAC,QAAQ,CAAC,OAAwB;QACrC,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,GAAG,OAAO,CAAC;QAE1C,MAAM,gBAAgB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;YAC7C,QAAQ,EAAE,CAAC,GAAG,IAAI,CAAC,IAAI,WAAW,EAAE,YAAY,EAAE,OAAO,CAAC;YAC1D,SAAS,EAAE,CAAC;YACZ,OAAO,EAAE,KAAK,IAAI,EAAE;gBAClB,MAAM,GAAG,GAAG,IAAI,GAAG,CACjB,GAAG,uBAAA,IAAI,0DAAO,UAAU,kBAAkB,CAAC,YAAY,CAAC,UAAU,CACnE,CAAC;gBACF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;oBAC7B,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC;gBAC7C,CAAC;gBACD,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,EAAE,CAAC,CAAC;gBACnE,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EACX,QAAQ,EACR,4CAAyB,CAAC,eAAe,CAC1C,CAAC;gBACF,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;gBAC3C,IAAI,CAAC,IAAA,gBAAE,EAAC,YAAY,EAAE,sBAAsB,CAAC,EAAE,CAAC;oBAC9C,MAAM,IAAI,KAAK,CAAC,4CAAyB,CAAC,yBAAyB,CAAC,CAAC;gBACvE,CAAC;gBACD,OAAO,YAAgC,CAAC;YAC1C,CAAC;SACF,CAAC,CAAC;QAEH,OAAO,gBAAgB,CAAC;IAC1B,CAAC;CAiEF;AA3XD,sCA2XC;;IApXG,OAAO,GAAG,uBAAA,IAAI,8BAAS,SAAS,CAAC;AACnC,CAAC;IAGC,OAAO,GAAG,uBAAA,IAAI,8BAAS,SAAS,CAAC;AACnC,CAAC,qEA0BoB,QAAkB,EAAE,OAAe;IACtD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,IAAI,4BAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,GAAG,OAAO,KAAK,QAAQ,CAAC,MAAM,EAAE,CAAC,CAAC;IACzE,CAAC;AACH,CAAC;AAkRD;;;;;;GAMG;AACH,KAAK,wCACH,MAAyB,EACzB,OAA8B;IAE9B,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,OAAO,CAAC;IAE1D,MAAM,aAAa,GACjB,MAAM,KAAK,MAAM;QACf,CAAC,CAAC,4CAAyB,CAAC,2BAA2B;QACvD,CAAC,CAAC,4CAAyB,CAAC,6BAA6B,CAAC;IAC9D,MAAM,cAAc,GAClB,MAAM,KAAK,MAAM;QACf,CAAC,CAAC,4CAAyB,CAAC,qCAAqC;QACjE,CAAC,CAAC,4CAAyB,CAAC,uCAAuC,CAAC;IAExE,MAAM,iBAAiB,GAAG,MAAM,IAAI,CAAC,UAAU,CAAC;QAC9C,QAAQ,EAAE;YACR,GAAG,IAAI,CAAC,IAAI,SAAS,MAAM,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,WAAW;YACrE,WAAW;YACX,KAAK,IAAI,IAAI;YACb,gEAAgE;YAChE,8DAA8D;YAC9D,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;YAC3C,KAAK,IAAI,IAAI;YACb,IAAI,IAAI,IAAI;SACb;QACD,OAAO,EAAE,KAAK,IAAI,EAAE;YAClB,MAAM,GAAG,GAAG,IAAI,GAAG,CACjB,GAAG,uBAAA,IAAI,0DAAO,YAAY,kBAAkB,CAAC,WAAW,CAAC,cAAc,MAAM,EAAE,CAChF,CAAC;YACF,IAAI,KAAK,EAAE,CAAC;gBACV,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;YAC1C,CAAC;YACD,0DAA0D;YAC1D,IAAI,IAAI,IAAI,MAAM,KAAK,QAAQ,EAAE,CAAC;gBAChC,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;YACxC,CAAC;YACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;gBACxB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;YAClD,CAAC;YACD,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;gBACvB,GAAG,CAAC,YAAY,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;YAChD,CAAC;YAED,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YAC7C,uBAAA,EAAa,uCAAc,MAA3B,EAAa,EAAe,QAAQ,EAAE,aAAa,CAAC,CAAC;YACrD,MAAM,aAAa,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;YAC5C,IAAI,CAAC,IAAA,gBAAE,EAAC,aAAa,EAAE,uBAAuB,CAAC,EAAE,CAAC;gBAChD,MAAM,IAAI,KAAK,CAAC,cAAc,CAAC,CAAC;YAClC,CAAC;YACD,OAAO,aAAkC,CAAC;QAC5C,CAAC;KACF,CAAC,CAAC;IAEH,OAAO,iBAAiB,CAAC;AAC3B,CAAC","sourcesContent":["import type {\n DataServiceCacheUpdatedEvent,\n DataServiceGranularCacheUpdatedEvent,\n DataServiceInvalidateQueriesAction,\n} from '@metamask/base-data-service';\nimport { BaseDataService } from '@metamask/base-data-service';\nimport type { CreateServicePolicyOptions } from '@metamask/controller-utils';\nimport { HttpError } from '@metamask/controller-utils';\nimport type { Messenger } from '@metamask/messenger';\nimport {\n array,\n boolean,\n is,\n nullable,\n number,\n optional,\n record,\n string,\n type as structType,\n} from '@metamask/superstruct';\n\nimport { serviceName, SocialServiceErrorMessage } from './social-constants';\nimport type {\n FetchFollowersOptions,\n FetchFollowingOptions,\n FetchLeaderboardOptions,\n FetchPositionsOptions,\n FetchTraderProfileOptions,\n FollowersResponse,\n FollowingResponse,\n FollowOptions,\n FollowResponse,\n LeaderboardResponse,\n PositionsResponse,\n TraderProfileResponse,\n UnfollowOptions,\n UnfollowResponse,\n} from './social-types';\nimport type { SocialServiceMethodActions } from './SocialService-method-action-types';\n\n// ---------------------------------------------------------------------------\n// Superstruct validation schemas\n// ---------------------------------------------------------------------------\n\nconst SocialHandlesStruct = structType({\n twitter: optional(nullable(string())),\n farcaster: optional(nullable(string())),\n ens: optional(nullable(string())),\n lens: optional(nullable(string())),\n});\n\nconst ProfileSummaryStruct = structType({\n profileId: string(),\n address: string(),\n name: string(),\n imageUrl: optional(nullable(string())),\n});\n\nconst TradeStruct = structType({\n direction: string(),\n tokenAmount: number(),\n usdCost: number(),\n timestamp: number(),\n transactionHash: string(),\n});\n\nconst PositionStruct = structType({\n tokenSymbol: string(),\n tokenName: string(),\n tokenAddress: string(),\n chain: string(),\n positionAmount: number(),\n boughtUsd: number(),\n soldUsd: number(),\n realizedPnl: number(),\n costBasis: number(),\n trades: array(TradeStruct),\n lastTradeAt: number(),\n currentValueUSD: optional(nullable(number())),\n pnlValueUsd: optional(nullable(number())),\n pnlPercent: optional(nullable(number())),\n});\n\nconst PaginationStruct = structType({\n hasMore: boolean(),\n nextPage: optional(number()),\n});\n\nconst LeaderboardEntryStruct = structType({\n rank: number(),\n addresses: array(string()),\n profileId: string(),\n name: string(),\n imageUrl: optional(nullable(string())),\n pnl30d: number(),\n winRate30d: optional(nullable(number())),\n roiPercent30d: optional(nullable(number())),\n tradeCount30d: optional(nullable(number())),\n pnl7d: optional(nullable(number())),\n winRate7d: optional(nullable(number())),\n roiPercent7d: optional(nullable(number())),\n tradeCount7d: optional(nullable(number())),\n pnlPerChain: record(string(), number()),\n followerCount: number(),\n socialHandles: SocialHandlesStruct,\n});\n\nconst LeaderboardResponseStruct = structType({\n traders: array(LeaderboardEntryStruct),\n});\n\nconst TraderProfileStruct = structType({\n profileId: string(),\n address: string(),\n allAddresses: array(string()),\n name: string(),\n imageUrl: optional(nullable(string())),\n});\n\nconst TraderStatsStruct = structType({\n pnl30d: optional(nullable(number())),\n winRate30d: optional(nullable(number())),\n roiPercent30d: optional(nullable(number())),\n tradeCount30d: optional(nullable(number())),\n pnl7d: optional(nullable(number())),\n winRate7d: optional(nullable(number())),\n roiPercent7d: optional(nullable(number())),\n tradeCount7d: optional(nullable(number())),\n});\n\nconst PerChainBreakdownStruct = structType({\n perChainPnl: record(string(), number()),\n perChainRoi: record(string(), nullable(number())),\n perChainVolume: record(string(), number()),\n});\n\nconst TraderProfileResponseStruct = structType({\n profile: TraderProfileStruct,\n stats: TraderStatsStruct,\n perChainBreakdown: PerChainBreakdownStruct,\n socialHandles: SocialHandlesStruct,\n followerCount: number(),\n followingCount: number(),\n});\n\nconst PositionsResponseStruct = structType({\n positions: array(PositionStruct),\n pagination: PaginationStruct,\n computedAt: optional(nullable(string())),\n});\n\nconst FollowersResponseStruct = structType({\n followers: array(ProfileSummaryStruct),\n count: number(),\n});\n\nconst FollowingResponseStruct = structType({\n following: array(ProfileSummaryStruct),\n count: number(),\n});\n\nconst FollowResponseStruct = structType({\n followed: array(ProfileSummaryStruct),\n});\n\nconst UnfollowResponseStruct = structType({\n unfollowed: array(ProfileSummaryStruct),\n});\n\n// ---------------------------------------------------------------------------\n// Messenger types\n// ---------------------------------------------------------------------------\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'fetchLeaderboard',\n 'fetchTraderProfile',\n 'fetchOpenPositions',\n 'fetchClosedPositions',\n 'fetchFollowers',\n 'fetchFollowing',\n 'follow',\n 'unfollow',\n] as const;\n\nexport type SocialServiceActions =\n | SocialServiceMethodActions\n | DataServiceInvalidateQueriesAction<typeof serviceName>;\n\nexport type SocialServiceEvents =\n | DataServiceCacheUpdatedEvent<typeof serviceName>\n | DataServiceGranularCacheUpdatedEvent<typeof serviceName>;\n\nexport type SocialServiceMessenger = Messenger<\n typeof serviceName,\n SocialServiceActions,\n SocialServiceEvents\n>;\n\n// ---------------------------------------------------------------------------\n// Service\n// ---------------------------------------------------------------------------\n\n/**\n * Data service wrapping social-api endpoints.\n */\nexport class SocialService extends BaseDataService<\n typeof serviceName,\n SocialServiceMessenger\n> {\n readonly #baseUrl: string;\n\n get #v1Url(): string {\n return `${this.#baseUrl}/api/v1`;\n }\n\n get #v2Url(): string {\n return `${this.#baseUrl}/api/v2`;\n }\n\n constructor({\n messenger,\n baseUrl,\n policyOptions,\n }: {\n messenger: SocialServiceMessenger;\n baseUrl: string;\n policyOptions?: CreateServicePolicyOptions;\n }) {\n super({ name: serviceName, messenger, policyOptions });\n this.#baseUrl = baseUrl;\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Throws an HttpError if the response is not ok.\n *\n * @param response - The fetch response to check.\n * @param message - The error message prefix from SocialServiceErrorMessage.\n */\n static #throwIfNotOk(response: Response, message: string): void {\n if (!response.ok) {\n throw new HttpError(response.status, `${message}: ${response.status}`);\n }\n }\n\n /**\n * Fetches the leaderboard of top traders.\n *\n * Calls `GET ${baseUrl}/leaderboard`.\n *\n * @param options - Optional query parameters for sorting, chain filtering, and limit.\n * @returns The leaderboard response with ranked traders.\n */\n async fetchLeaderboard(\n options?: FetchLeaderboardOptions,\n ): Promise<LeaderboardResponse> {\n const leaderboardResponse = await this.fetchQuery({\n queryKey: [`${this.name}:fetchLeaderboard`, options ?? null],\n queryFn: async () => {\n const { sort, chains, limit } = options ?? {};\n const url = new URL(`${this.#v1Url}/leaderboard`);\n if (sort) {\n url.searchParams.append('sort', sort);\n }\n if (chains) {\n for (const chain of chains) {\n url.searchParams.append('chains', chain);\n }\n }\n if (limit !== undefined) {\n url.searchParams.append('limit', String(limit));\n }\n\n const response = await fetch(url.toString());\n SocialService.#throwIfNotOk(\n response,\n SocialServiceErrorMessage.FETCH_LEADERBOARD_FAILED,\n );\n const leaderboardData = await response.json();\n if (!is(leaderboardData, LeaderboardResponseStruct)) {\n throw new Error(\n SocialServiceErrorMessage.FETCH_LEADERBOARD_INVALID_RESPONSE,\n );\n }\n return leaderboardData as LeaderboardResponse;\n },\n });\n\n return leaderboardResponse;\n }\n\n /**\n * Fetches a trader's profile by address or profile ID.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @returns The trader profile response.\n */\n async fetchTraderProfile(\n options: FetchTraderProfileOptions,\n ): Promise<TraderProfileResponse> {\n const { addressOrId } = options;\n\n const traderProfileResponse = await this.fetchQuery({\n queryKey: [`${this.name}:fetchTraderProfile`, addressOrId],\n queryFn: async () => {\n const url = `${this.#v1Url}/traders/${encodeURIComponent(addressOrId)}/profile`;\n const response = await fetch(url);\n SocialService.#throwIfNotOk(\n response,\n SocialServiceErrorMessage.FETCH_TRADER_PROFILE_FAILED,\n );\n const traderProfileData = await response.json();\n if (!is(traderProfileData, TraderProfileResponseStruct)) {\n throw new Error(\n SocialServiceErrorMessage.FETCH_TRADER_PROFILE_INVALID_RESPONSE,\n );\n }\n return traderProfileData as TraderProfileResponse;\n },\n });\n\n return traderProfileResponse;\n }\n\n /**\n * Fetches a trader's open positions.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/positions/open`.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @param options.chain - Filter by chain.\n * @param options.sort - Sort by 'value' or 'latest'.\n * @param options.limit - Number of results per page.\n * @param options.page - Page number (1-based).\n * @returns The positions response.\n */\n async fetchOpenPositions(\n options: FetchPositionsOptions,\n ): Promise<PositionsResponse> {\n return this.#fetchPositions('open', options);\n }\n\n /**\n * Fetches a trader's closed positions.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/positions/closed`.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @param options.chain - Filter by chain.\n * @param options.sort - Sort by 'value' or 'latest'.\n * @param options.limit - Number of results per page.\n * @param options.page - Page number (1-based).\n * @returns The positions response.\n */\n async fetchClosedPositions(\n options: FetchPositionsOptions,\n ): Promise<PositionsResponse> {\n return this.#fetchPositions('closed', options);\n }\n\n /**\n * Fetches a trader's MetaMask followers.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/followers`.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @returns The followers response.\n */\n async fetchFollowers(\n options: FetchFollowersOptions,\n ): Promise<FollowersResponse> {\n const { addressOrId } = options;\n\n const followersResponse = await this.fetchQuery({\n queryKey: [`${this.name}:fetchFollowers`, addressOrId],\n queryFn: async () => {\n const url = `${this.#v1Url}/traders/${encodeURIComponent(addressOrId)}/followers`;\n const response = await fetch(url);\n SocialService.#throwIfNotOk(\n response,\n SocialServiceErrorMessage.FETCH_FOLLOWERS_FAILED,\n );\n const followersData = await response.json();\n if (!is(followersData, FollowersResponseStruct)) {\n throw new Error(\n SocialServiceErrorMessage.FETCH_FOLLOWERS_INVALID_RESPONSE,\n );\n }\n return followersData as FollowersResponse;\n },\n });\n\n return followersResponse;\n }\n\n /**\n * Fetches the list of traders a user is following.\n *\n * Calls `GET ${baseUrl}/users/${addressOrUid}/following`.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID.\n * @returns The following response.\n */\n async fetchFollowing(\n options: FetchFollowingOptions,\n ): Promise<FollowingResponse> {\n const { addressOrUid } = options;\n\n const followingResponse = await this.fetchQuery({\n queryKey: [`${this.name}:fetchFollowing`, addressOrUid],\n staleTime: 0,\n queryFn: async () => {\n const url = `${this.#v1Url}/users/${encodeURIComponent(addressOrUid)}/following`;\n const response = await fetch(url);\n SocialService.#throwIfNotOk(\n response,\n SocialServiceErrorMessage.FETCH_FOLLOWING_FAILED,\n );\n const followingData = await response.json();\n if (!is(followingData, FollowingResponseStruct)) {\n throw new Error(\n SocialServiceErrorMessage.FETCH_FOLLOWING_INVALID_RESPONSE,\n );\n }\n return followingData as FollowingResponse;\n },\n });\n\n return followingResponse;\n }\n\n /**\n * Follows one or more traders.\n *\n * Calls `PUT ${baseUrl}/users/${addressOrUid}/follows`.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the user.\n * @param options.targets - Array of wallet addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\n async follow(options: FollowOptions): Promise<FollowResponse> {\n const { addressOrUid, targets } = options;\n\n const followResponse = await this.fetchQuery({\n queryKey: [`${this.name}:follow`, addressOrUid, targets],\n staleTime: 0,\n queryFn: async () => {\n const url = `${this.#v1Url}/users/${encodeURIComponent(addressOrUid)}/follows`;\n const response = await fetch(url, {\n method: 'PUT',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify({ targets }),\n });\n SocialService.#throwIfNotOk(\n response,\n SocialServiceErrorMessage.FOLLOW_FAILED,\n );\n const followData = await response.json();\n if (!is(followData, FollowResponseStruct)) {\n throw new Error(SocialServiceErrorMessage.FOLLOW_INVALID_RESPONSE);\n }\n return followData as FollowResponse;\n },\n });\n\n return followResponse;\n }\n\n /**\n * Unfollows one or more traders.\n *\n * Calls `DELETE ${baseUrl}/users/${addressOrUid}/follows?targets=...`.\n * Targets are sent as query params because Fastify does not parse\n * request bodies on DELETE requests per RFC 9110.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the user.\n * @param options.targets - Array of wallet addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\n async unfollow(options: UnfollowOptions): Promise<UnfollowResponse> {\n const { addressOrUid, targets } = options;\n\n const unfollowResponse = await this.fetchQuery({\n queryKey: [`${this.name}:unfollow`, addressOrUid, targets],\n staleTime: 0,\n queryFn: async () => {\n const url = new URL(\n `${this.#v1Url}/users/${encodeURIComponent(addressOrUid)}/follows`,\n );\n for (const target of targets) {\n url.searchParams.append('targets', target);\n }\n const response = await fetch(url.toString(), { method: 'DELETE' });\n SocialService.#throwIfNotOk(\n response,\n SocialServiceErrorMessage.UNFOLLOW_FAILED,\n );\n const unfollowData = await response.json();\n if (!is(unfollowData, UnfollowResponseStruct)) {\n throw new Error(SocialServiceErrorMessage.UNFOLLOW_INVALID_RESPONSE);\n }\n return unfollowData as UnfollowResponse;\n },\n });\n\n return unfollowResponse;\n }\n\n /**\n * Shared helper for fetching open/closed positions.\n *\n * @param status - \"open\" or \"closed\".\n * @param options - Options bag including addressOrId and query parameters.\n * @returns The positions response.\n */\n async #fetchPositions(\n status: 'open' | 'closed',\n options: FetchPositionsOptions,\n ): Promise<PositionsResponse> {\n const { addressOrId, chain, sort, limit, page } = options;\n\n const failedMessage =\n status === 'open'\n ? SocialServiceErrorMessage.FETCH_OPEN_POSITIONS_FAILED\n : SocialServiceErrorMessage.FETCH_CLOSED_POSITIONS_FAILED;\n const invalidMessage =\n status === 'open'\n ? SocialServiceErrorMessage.FETCH_OPEN_POSITIONS_INVALID_RESPONSE\n : SocialServiceErrorMessage.FETCH_CLOSED_POSITIONS_INVALID_RESPONSE;\n\n const positionsResponse = await this.fetchQuery({\n queryKey: [\n `${this.name}:fetch${status === 'open' ? 'Open' : 'Closed'}Positions`,\n addressOrId,\n chain ?? null,\n // sort is not used for open positions (v2 endpoint dropped it),\n // so exclude it from the key to avoid redundant cache entries\n status === 'closed' ? (sort ?? null) : null,\n limit ?? null,\n page ?? null,\n ],\n queryFn: async () => {\n const url = new URL(\n `${this.#v2Url}/traders/${encodeURIComponent(addressOrId)}/positions/${status}`,\n );\n if (chain) {\n url.searchParams.append('chain', chain);\n }\n // sort is not supported on the v2 open-positions endpoint\n if (sort && status === 'closed') {\n url.searchParams.append('sort', sort);\n }\n if (limit !== undefined) {\n url.searchParams.append('limit', String(limit));\n }\n if (page !== undefined) {\n url.searchParams.append('page', String(page));\n }\n\n const response = await fetch(url.toString());\n SocialService.#throwIfNotOk(response, failedMessage);\n const positionsData = await response.json();\n if (!is(positionsData, PositionsResponseStruct)) {\n throw new Error(invalidMessage);\n }\n return positionsData as PositionsResponse;\n },\n });\n\n return positionsResponse;\n }\n}\n"]}
@@ -0,0 +1,113 @@
1
+ import type { DataServiceCacheUpdatedEvent, DataServiceGranularCacheUpdatedEvent, DataServiceInvalidateQueriesAction } from "@metamask/base-data-service";
2
+ import { BaseDataService } from "@metamask/base-data-service";
3
+ import type { CreateServicePolicyOptions } from "@metamask/controller-utils";
4
+ import type { Messenger } from "@metamask/messenger";
5
+ import { serviceName } from "./social-constants.cjs";
6
+ import type { FetchFollowersOptions, FetchFollowingOptions, FetchLeaderboardOptions, FetchPositionsOptions, FetchTraderProfileOptions, FollowersResponse, FollowingResponse, FollowOptions, FollowResponse, LeaderboardResponse, PositionsResponse, TraderProfileResponse, UnfollowOptions, UnfollowResponse } from "./social-types.cjs";
7
+ import type { SocialServiceMethodActions } from "./SocialService-method-action-types.cjs";
8
+ export type SocialServiceActions = SocialServiceMethodActions | DataServiceInvalidateQueriesAction<typeof serviceName>;
9
+ export type SocialServiceEvents = DataServiceCacheUpdatedEvent<typeof serviceName> | DataServiceGranularCacheUpdatedEvent<typeof serviceName>;
10
+ export type SocialServiceMessenger = Messenger<typeof serviceName, SocialServiceActions, SocialServiceEvents>;
11
+ /**
12
+ * Data service wrapping social-api endpoints.
13
+ */
14
+ export declare class SocialService extends BaseDataService<typeof serviceName, SocialServiceMessenger> {
15
+ #private;
16
+ constructor({ messenger, baseUrl, policyOptions, }: {
17
+ messenger: SocialServiceMessenger;
18
+ baseUrl: string;
19
+ policyOptions?: CreateServicePolicyOptions;
20
+ });
21
+ /**
22
+ * Fetches the leaderboard of top traders.
23
+ *
24
+ * Calls `GET ${baseUrl}/leaderboard`.
25
+ *
26
+ * @param options - Optional query parameters for sorting, chain filtering, and limit.
27
+ * @returns The leaderboard response with ranked traders.
28
+ */
29
+ fetchLeaderboard(options?: FetchLeaderboardOptions): Promise<LeaderboardResponse>;
30
+ /**
31
+ * Fetches a trader's profile by address or profile ID.
32
+ *
33
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.
34
+ *
35
+ * @param options - Options bag.
36
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
37
+ * @returns The trader profile response.
38
+ */
39
+ fetchTraderProfile(options: FetchTraderProfileOptions): Promise<TraderProfileResponse>;
40
+ /**
41
+ * Fetches a trader's open positions.
42
+ *
43
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/positions/open`.
44
+ *
45
+ * @param options - Options bag.
46
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
47
+ * @param options.chain - Filter by chain.
48
+ * @param options.sort - Sort by 'value' or 'latest'.
49
+ * @param options.limit - Number of results per page.
50
+ * @param options.page - Page number (1-based).
51
+ * @returns The positions response.
52
+ */
53
+ fetchOpenPositions(options: FetchPositionsOptions): Promise<PositionsResponse>;
54
+ /**
55
+ * Fetches a trader's closed positions.
56
+ *
57
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/positions/closed`.
58
+ *
59
+ * @param options - Options bag.
60
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
61
+ * @param options.chain - Filter by chain.
62
+ * @param options.sort - Sort by 'value' or 'latest'.
63
+ * @param options.limit - Number of results per page.
64
+ * @param options.page - Page number (1-based).
65
+ * @returns The positions response.
66
+ */
67
+ fetchClosedPositions(options: FetchPositionsOptions): Promise<PositionsResponse>;
68
+ /**
69
+ * Fetches a trader's MetaMask followers.
70
+ *
71
+ * Calls `GET ${baseUrl}/traders/${addressOrId}/followers`.
72
+ *
73
+ * @param options - Options bag.
74
+ * @param options.addressOrId - Wallet address or Clicker profile ID.
75
+ * @returns The followers response.
76
+ */
77
+ fetchFollowers(options: FetchFollowersOptions): Promise<FollowersResponse>;
78
+ /**
79
+ * Fetches the list of traders a user is following.
80
+ *
81
+ * Calls `GET ${baseUrl}/users/${addressOrUid}/following`.
82
+ *
83
+ * @param options - Options bag.
84
+ * @param options.addressOrUid - Wallet address or Clicker profile ID.
85
+ * @returns The following response.
86
+ */
87
+ fetchFollowing(options: FetchFollowingOptions): Promise<FollowingResponse>;
88
+ /**
89
+ * Follows one or more traders.
90
+ *
91
+ * Calls `PUT ${baseUrl}/users/${addressOrUid}/follows`.
92
+ *
93
+ * @param options - Options bag.
94
+ * @param options.addressOrUid - Wallet address or Clicker profile ID of the user.
95
+ * @param options.targets - Array of wallet addresses or profile IDs to follow.
96
+ * @returns The follow response with confirmed follows.
97
+ */
98
+ follow(options: FollowOptions): Promise<FollowResponse>;
99
+ /**
100
+ * Unfollows one or more traders.
101
+ *
102
+ * Calls `DELETE ${baseUrl}/users/${addressOrUid}/follows?targets=...`.
103
+ * Targets are sent as query params because Fastify does not parse
104
+ * request bodies on DELETE requests per RFC 9110.
105
+ *
106
+ * @param options - Options bag.
107
+ * @param options.addressOrUid - Wallet address or Clicker profile ID of the user.
108
+ * @param options.targets - Array of wallet addresses or profile IDs to unfollow.
109
+ * @returns The unfollow response with confirmed unfollows.
110
+ */
111
+ unfollow(options: UnfollowOptions): Promise<UnfollowResponse>;
112
+ }
113
+ //# sourceMappingURL=SocialService.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SocialService.d.cts","sourceRoot":"","sources":["../src/SocialService.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,4BAA4B,EAC5B,oCAAoC,EACpC,kCAAkC,EACnC,oCAAoC;AACrC,OAAO,EAAE,eAAe,EAAE,oCAAoC;AAC9D,OAAO,KAAK,EAAE,0BAA0B,EAAE,mCAAmC;AAE7E,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAarD,OAAO,EAAE,WAAW,EAA6B,+BAA2B;AAC5E,OAAO,KAAK,EACV,qBAAqB,EACrB,qBAAqB,EACrB,uBAAuB,EACvB,qBAAqB,EACrB,yBAAyB,EACzB,iBAAiB,EACjB,iBAAiB,EACjB,aAAa,EACb,cAAc,EACd,mBAAmB,EACnB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EACjB,2BAAuB;AACxB,OAAO,KAAK,EAAE,0BAA0B,EAAE,gDAA4C;AAkJtF,MAAM,MAAM,oBAAoB,GAC5B,0BAA0B,GAC1B,kCAAkC,CAAC,OAAO,WAAW,CAAC,CAAC;AAE3D,MAAM,MAAM,mBAAmB,GAC3B,4BAA4B,CAAC,OAAO,WAAW,CAAC,GAChD,oCAAoC,CAAC,OAAO,WAAW,CAAC,CAAC;AAE7D,MAAM,MAAM,sBAAsB,GAAG,SAAS,CAC5C,OAAO,WAAW,EAClB,oBAAoB,EACpB,mBAAmB,CACpB,CAAC;AAMF;;GAEG;AACH,qBAAa,aAAc,SAAQ,eAAe,CAChD,OAAO,WAAW,EAClB,sBAAsB,CACvB;;gBAWa,EACV,SAAS,EACT,OAAO,EACP,aAAa,GACd,EAAE;QACD,SAAS,EAAE,sBAAsB,CAAC;QAClC,OAAO,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,0BAA0B,CAAC;KAC5C;IAsBD;;;;;;;OAOG;IACG,gBAAgB,CACpB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAoC/B;;;;;;;;OAQG;IACG,kBAAkB,CACtB,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,qBAAqB,CAAC;IAyBjC;;;;;;;;;;;;OAYG;IACG,kBAAkB,CACtB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IAI7B;;;;;;;;;;;;OAYG;IACG,oBAAoB,CACxB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IAI7B;;;;;;;;OAQG;IACG,cAAc,CAClB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IAyB7B;;;;;;;;OAQG;IACG,cAAc,CAClB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;IA0B7B;;;;;;;;;OASG;IACG,MAAM,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IA4B7D;;;;;;;;;;;OAWG;IACG,QAAQ,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;CA4FpE"}