@metamask/social-controllers 3.7.0 → 3.9.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/CHANGELOG.md CHANGED
@@ -7,6 +7,37 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [3.9.0]
11
+
12
+ ### Added
13
+
14
+ - Add optional `createdAt` to `TraderProfile`. `fetchTraderProfile` accepts an ISO-8601 timestamp, or `null`, on `GET /traders/:addressOrId/profile` and still accepts responses that omit it ([#10877](https://github.com/MetaMask/core/pull/10877))
15
+ - Add the shared `all` feed scope to `FetchFeedOptions` and export `FeedScope`. Preserve optional `eventId`, `revision`, and `occurredAt` projection metadata on `FeedItem` ([#10865](https://github.com/MetaMask/core/pull/10865))
16
+ - Add the `trending` feed scope to `FetchFeedOptions` and export `FeedScope` for policy-filtered trending feed reads ([#10895](https://github.com/MetaMask/core/pull/10895))
17
+ - Add explicit `all` and `trending` scope subscriptions to `SocialRealtimeService` and validate hydrated realtime feed events before forwarding them ([#10924](https://github.com/MetaMask/core/pull/10924))
18
+
19
+ ### Changed
20
+
21
+ - Bump `@metamask/core-backend` from `^12.1.0` to `^12.3.0` ([#10857](https://github.com/MetaMask/core/pull/10857), [#10876](https://github.com/MetaMask/core/pull/10876))
22
+ - Bump `@metamask/base-controller` from `^10.0.0` to `^10.1.0` ([#10864](https://github.com/MetaMask/core/pull/10864))
23
+ - Bump `@metamask/profile-sync-controller` from `^34.0.3` to `^35.0.0` ([#10905](https://github.com/MetaMask/core/pull/10905), [#10925](https://github.com/MetaMask/core/pull/10925))
24
+
25
+ ## [3.8.0]
26
+
27
+ ### Added
28
+
29
+ - Add `createCopyTradeIntent` method to `SocialService` (and the `SocialService:createCopyTradeIntent` messenger action). Calls `POST /v1/copy-trade-intents` with the comment origin, the copier's CAIP-10 account, and the execution (a swaps `quoteId` or a perps `oid`), and returns the validated `CopyTradeIntentResponse`. Both 201 (created) and 200 (existing intent) resolve ([#10823](https://github.com/MetaMask/core/pull/10823))
30
+ - Export the `CreateCopyTradeIntentOptions`, `CopyTradeIntentResponse`, `CopyTradeOrigin`, `CopyTradeExecution`, `CopyTradeAccount`, and `CopyTradePayoutEligibility` types
31
+
32
+ ### Changed
33
+
34
+ - Preserve optional per-position copy counts from Social API responses ([#10801](https://github.com/MetaMask/core/pull/10801))
35
+ - Bump `@metamask/core-backend` from `^12.0.1` to `^12.1.0` ([#10788](https://github.com/MetaMask/core/pull/10788))
36
+
37
+ ### Fixed
38
+
39
+ - Set `staleTime: 0` on `fetchFollowers` and `fetchTraderFollowing` so follow-list refetches after follow/unfollow are not served from the 1-minute `BaseDataService` cache ([#10789](https://github.com/MetaMask/core/pull/10789))
40
+
10
41
  ## [3.7.0]
11
42
 
12
43
  ### Added
@@ -266,7 +297,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
266
297
  - `unfollowTrader` — unfollows traders and removes addresses from state
267
298
  - `updateFollowing` — fetches following list and replaces addresses in state
268
299
 
269
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.7.0...HEAD
300
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.9.0...HEAD
301
+ [3.9.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.8.0...@metamask/social-controllers@3.9.0
302
+ [3.8.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.7.0...@metamask/social-controllers@3.8.0
270
303
  [3.7.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.6.0...@metamask/social-controllers@3.7.0
271
304
  [3.6.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.5.0...@metamask/social-controllers@3.6.0
272
305
  [3.5.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@3.4.0...@metamask/social-controllers@3.5.0
@@ -1,6 +1,10 @@
1
1
  import type { BackendWebSocketServiceMessenger } from '@metamask/core-backend';
2
- import type { FeedItem } from './social-types.js';
3
- export declare const SOCIAL_FEED_CHANNEL: 'social.v1.feed.trending';
2
+ import type { SocialRealtimeFeedItem } from './structs.js';
3
+ export declare const SOCIAL_FEED_CHANNELS: {
4
+ readonly all: 'social.v1.feed.all';
5
+ readonly trending: 'social.v1.feed.trending';
6
+ };
7
+ export type SocialFeedRealtimeScope = keyof typeof SOCIAL_FEED_CHANNELS;
4
8
  export declare const SOCIAL_FEED_CHANNEL_TYPE: 'social.v1';
5
9
  export type SocialFeedEvent = {
6
10
  version: 1;
@@ -9,26 +13,28 @@ export type SocialFeedEvent = {
9
13
  feedItemId: string;
10
14
  revision: number;
11
15
  occurredAt: string;
12
- data: FeedItem;
16
+ data: SocialRealtimeFeedItem;
13
17
  };
14
- export type SocialFeedEventListener = (event: SocialFeedEvent) => void;
18
+ export type SocialFeedEventListener = (event: SocialFeedEvent, scope: SocialFeedRealtimeScope) => void;
15
19
  export type SocialFeedReconnectListener = () => void;
16
20
  export type SocialRealtimeServiceOptions = {
17
21
  messenger: BackendWebSocketServiceMessenger;
22
+ scopes: readonly SocialFeedRealtimeScope[];
18
23
  isEnabled?: () => boolean;
19
24
  };
20
25
  /**
21
26
  * Social realtime subscription service built on the shared backend WebSocket.
22
27
  *
23
- * The POC subscribes to the global feed channel. Additional Social channels
24
- * can be added here without creating another WebSocket connection.
28
+ * Clients explicitly select one or more global feed scopes. Additional Social
29
+ * channels can be added here without creating another WebSocket connection.
25
30
  */
26
31
  export declare class SocialRealtimeService {
27
32
  #private;
28
33
  readonly name: 'SocialRealtimeService';
29
- constructor({ messenger, isEnabled, }: SocialRealtimeServiceOptions);
34
+ constructor({ messenger, scopes, isEnabled, }: SocialRealtimeServiceOptions);
30
35
  addListener(listener: SocialFeedEventListener): () => void;
31
36
  addReconnectListener(listener: SocialFeedReconnectListener): () => void;
37
+ setScopes(scopes: readonly SocialFeedRealtimeScope[]): Promise<void>;
32
38
  setActive(active: boolean): Promise<void>;
33
39
  }
34
40
  //# sourceMappingURL=SocialRealtimeService.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SocialRealtimeService.d.ts","sourceRoot":"","sources":["../src/SocialRealtimeService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gCAAgC,EAGjC,MAAM,wBAAwB,CAAC;AAEhC,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAElD,eAAO,MAAM,mBAAmB,EAAG,yBAAkC,CAAC;AACtE,eAAO,MAAM,wBAAwB,EAAG,WAAoB,CAAC;AAE7D,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,CAAC,KAAK,EAAE,eAAe,KAAK,IAAI,CAAC;AACvE,MAAM,MAAM,2BAA2B,GAAG,MAAM,IAAI,CAAC;AAErD,MAAM,MAAM,4BAA4B,GAAG;IACzC,SAAS,EAAE,gCAAgC,CAAC;IAC5C,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;CAC3B,CAAC;AAiCF;;;;;GAKG;AACH,qBAAa,qBAAqB;;IAChC,QAAQ,CAAC,IAAI,EAAG,uBAAuB,CAAU;IAkBjD,YAAY,EACV,SAAS,EACT,SAA+B,GAChC,EAAE,4BAA4B,EAyB9B;IAED,WAAW,CAAC,QAAQ,EAAE,uBAAuB,GAAG,MAAM,IAAI,CAGzD;IAED,oBAAoB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM,IAAI,CAGtE;IAEK,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAS9C;CAsEF"}
1
+ {"version":3,"file":"SocialRealtimeService.d.ts","sourceRoot":"","sources":["../src/SocialRealtimeService.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,gCAAgC,EAGjC,MAAM,wBAAwB,CAAC;AAGhC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,cAAc,CAAC;AAE3D,eAAO,MAAM,oBAAoB;aAC/B,GAAG,EAAE,oBAAoB;aACzB,QAAQ,EAAE,yBAAyB;CAC3B,CAAC;AAEX,MAAM,MAAM,uBAAuB,GAAG,MAAM,OAAO,oBAAoB,CAAC;AAExE,eAAO,MAAM,wBAAwB,EAAG,WAAoB,CAAC;AAE7D,MAAM,MAAM,eAAe,GAAG;IAC5B,OAAO,EAAE,CAAC,CAAC;IACX,IAAI,EAAE,WAAW,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,sBAAsB,CAAC;CAC9B,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAAG,CACpC,KAAK,EAAE,eAAe,EACtB,KAAK,EAAE,uBAAuB,KAC3B,IAAI,CAAC;AACV,MAAM,MAAM,2BAA2B,GAAG,MAAM,IAAI,CAAC;AAErD,MAAM,MAAM,4BAA4B,GAAG;IACzC,SAAS,EAAE,gCAAgC,CAAC;IAC5C,MAAM,EAAE,SAAS,uBAAuB,EAAE,CAAC;IAC3C,SAAS,CAAC,EAAE,MAAM,OAAO,CAAC;CAC3B,CAAC;AAmDF;;;;;GAKG;AACH,qBAAa,qBAAqB;;IAChC,QAAQ,CAAC,IAAI,EAAG,uBAAuB,CAAU;IA4BjD,YAAY,EACV,SAAS,EACT,MAAM,EACN,SAA+B,GAChC,EAAE,4BAA4B,EA6B9B;IAED,WAAW,CAAC,QAAQ,EAAE,uBAAuB,GAAG,MAAM,IAAI,CAGzD;IAED,oBAAoB,CAAC,QAAQ,EAAE,2BAA2B,GAAG,MAAM,IAAI,CAGtE;IAEK,SAAS,CAAC,MAAM,EAAE,SAAS,uBAAuB,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAiBzE;IA4BK,SAAS,CAAC,MAAM,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAU9C;CAuJF"}
@@ -1,21 +1,34 @@
1
1
  import { WebSocketState } from '@metamask/core-backend';
2
- export const SOCIAL_FEED_CHANNEL = 'social.v1.feed.trending';
2
+ import { parseSocialRealtimeFeedItem } from './structs.js';
3
+ export const SOCIAL_FEED_CHANNELS = {
4
+ all: 'social.v1.feed.all',
5
+ trending: 'social.v1.feed.trending',
6
+ };
3
7
  export const SOCIAL_FEED_CHANNEL_TYPE = 'social.v1';
4
8
  const isRecord = (value) => typeof value === 'object' && value !== null;
9
+ const normalizeScopes = (scopes) => {
10
+ const normalized = [...new Set(scopes)];
11
+ if (normalized.length === 0) {
12
+ throw new Error('At least one Social feed scope is required');
13
+ }
14
+ return normalized;
15
+ };
16
+ const scopeForChannel = (channel) => Object.entries(SOCIAL_FEED_CHANNELS).find(([, value]) => value === channel)?.[0] ?? undefined;
5
17
  const parseSocialFeedEvent = (data) => {
6
18
  if (!isRecord(data)) {
7
19
  return undefined;
8
20
  }
21
+ const feedItem = parseSocialRealtimeFeedItem(data.data);
9
22
  if (data.version !== 1 ||
10
23
  data.kind !== 'feed-item' ||
11
24
  typeof data.eventId !== 'string' ||
12
25
  typeof data.feedItemId !== 'string' ||
13
26
  typeof data.revision !== 'number' ||
14
27
  typeof data.occurredAt !== 'string' ||
15
- !isRecord(data.data)) {
28
+ feedItem === undefined) {
16
29
  return undefined;
17
30
  }
18
- return data;
31
+ return { ...data, data: feedItem };
19
32
  };
20
33
  const parseSocialFeedEvents = (data) => {
21
34
  const entries = Array.isArray(data) ? data : [data];
@@ -26,8 +39,8 @@ const parseSocialFeedEvents = (data) => {
26
39
  /**
27
40
  * Social realtime subscription service built on the shared backend WebSocket.
28
41
  *
29
- * The POC subscribes to the global feed channel. Additional Social channels
30
- * can be added here without creating another WebSocket connection.
42
+ * Clients explicitly select one or more global feed scopes. Additional Social
43
+ * channels can be added here without creating another WebSocket connection.
31
44
  */
32
45
  export class SocialRealtimeService {
33
46
  name = 'SocialRealtimeService';
@@ -35,27 +48,37 @@ export class SocialRealtimeService {
35
48
  #listeners = new Set();
36
49
  #reconnectListeners = new Set();
37
50
  #isEnabled;
51
+ #scopes;
52
+ #scopeUpdatePromise;
38
53
  #active = false;
39
54
  #subscription;
55
+ #subscriptionToken;
40
56
  #subscriptionPromise;
57
+ #pendingUnsubscriptions = new Set();
58
+ #connectionVersion = 0;
41
59
  #wasDisconnected = false;
42
- constructor({ messenger, isEnabled = () => true, }) {
60
+ constructor({ messenger, scopes, isEnabled = () => true, }) {
43
61
  this.#messenger = messenger;
62
+ this.#scopes = normalizeScopes(scopes);
44
63
  this.#isEnabled = isEnabled;
45
64
  this.#messenger.subscribe('BackendWebSocketService:connectionStateChanged', ({ state }) => {
46
65
  if (state === WebSocketState.DISCONNECTED) {
66
+ this.#connectionVersion += 1;
47
67
  this.#subscription = undefined;
68
+ this.#subscriptionToken = undefined;
48
69
  this.#wasDisconnected = true;
49
70
  }
50
71
  if (state === WebSocketState.CONNECTED && this.#active) {
51
72
  const isReconnect = this.#wasDisconnected;
52
73
  this.#wasDisconnected = false;
53
- // Subscription setup handles its own errors and must not block reconnect handling.
54
74
  // eslint-disable-next-line no-void
55
- void this.#subscribeToFeed();
56
- if (isReconnect) {
57
- this.#reconnectListeners.forEach((listener) => listener());
58
- }
75
+ void this.#subscribeToFeed()
76
+ .then(() => {
77
+ if (isReconnect) {
78
+ this.#reconnectListeners.forEach((listener) => listener());
79
+ }
80
+ })
81
+ .catch(() => undefined);
59
82
  }
60
83
  });
61
84
  }
@@ -67,12 +90,50 @@ export class SocialRealtimeService {
67
90
  this.#reconnectListeners.add(listener);
68
91
  return () => this.#reconnectListeners.delete(listener);
69
92
  }
93
+ async setScopes(scopes) {
94
+ const normalizedScopes = normalizeScopes(scopes);
95
+ const scopeUpdate = this.#scopeUpdatePromise
96
+ ? this.#scopeUpdatePromise
97
+ .catch(() => undefined)
98
+ .then(() => this.#applyScopes(normalizedScopes))
99
+ : this.#applyScopes(normalizedScopes);
100
+ this.#scopeUpdatePromise = scopeUpdate;
101
+ try {
102
+ await scopeUpdate;
103
+ }
104
+ finally {
105
+ if (this.#scopeUpdatePromise === scopeUpdate) {
106
+ this.#scopeUpdatePromise = Promise.resolve();
107
+ }
108
+ }
109
+ }
110
+ async #applyScopes(normalizedScopes) {
111
+ if (!this.#active) {
112
+ this.#scopes = normalizedScopes;
113
+ return;
114
+ }
115
+ const previousScopes = this.#scopes;
116
+ const connectionVersion = this.#connectionVersion;
117
+ this.#scopes = normalizedScopes;
118
+ try {
119
+ await this.#resubscribeToFeed();
120
+ }
121
+ catch (error) {
122
+ if (this.#active &&
123
+ this.#connectionVersion === connectionVersion &&
124
+ this.#subscription) {
125
+ this.#scopes = previousScopes;
126
+ }
127
+ throw error;
128
+ }
129
+ }
70
130
  async setActive(active) {
71
131
  this.#active = active && this.#isEnabled();
72
132
  if (!this.#active) {
73
133
  await this.#unsubscribeFromFeed();
74
134
  return;
75
135
  }
136
+ await this.#retryPendingUnsubscriptions();
76
137
  await this.#subscribeToFeed();
77
138
  }
78
139
  async #subscribeToFeed() {
@@ -86,25 +147,25 @@ export class SocialRealtimeService {
86
147
  }
87
148
  }
88
149
  const subscriptionPromise = Promise.resolve().then(async () => {
89
- try {
90
- await this.#messenger.call('BackendWebSocketService:connect');
91
- // Each service needs its own callback and subscription lifecycle.
92
- const subscription = await this.#messenger.call('BackendWebSocketService:subscribe', {
93
- channels: [SOCIAL_FEED_CHANNEL],
94
- channelType: SOCIAL_FEED_CHANNEL_TYPE,
95
- callback: (notification) => {
96
- this.#handleNotification(notification);
97
- },
98
- });
99
- if (!this.#active) {
100
- await subscription.unsubscribe();
101
- return;
102
- }
103
- this.#subscription = subscription;
104
- }
105
- catch {
106
- this.#subscription = undefined;
150
+ await this.#messenger.call('BackendWebSocketService:connect');
151
+ const subscriptionToken = Symbol('social-feed-subscription');
152
+ // Each service needs its own callback and subscription lifecycle.
153
+ const subscription = await this.#messenger.call('BackendWebSocketService:subscribe', {
154
+ channels: this.#scopes.map((scope) => SOCIAL_FEED_CHANNELS[scope]),
155
+ channelType: SOCIAL_FEED_CHANNEL_TYPE,
156
+ callback: (notification) => {
157
+ if (this.#subscriptionToken !== subscriptionToken) {
158
+ return;
159
+ }
160
+ this.#handleNotification(notification);
161
+ },
162
+ });
163
+ if (!this.#active) {
164
+ await subscription.unsubscribe();
165
+ return;
107
166
  }
167
+ this.#subscription = subscription;
168
+ this.#subscriptionToken = subscriptionToken;
108
169
  });
109
170
  this.#subscriptionPromise = subscriptionPromise;
110
171
  try {
@@ -114,19 +175,95 @@ export class SocialRealtimeService {
114
175
  this.#subscriptionPromise = undefined;
115
176
  }
116
177
  }
178
+ async #resubscribeToFeed() {
179
+ while (this.#subscriptionPromise) {
180
+ await this.#subscriptionPromise;
181
+ }
182
+ await this.#retryPendingUnsubscriptions();
183
+ const existingSubscription = this.#subscription;
184
+ const existingSubscriptionToken = this.#subscriptionToken;
185
+ const connectionVersion = this.#connectionVersion;
186
+ this.#subscription = undefined;
187
+ try {
188
+ await this.#subscribeToFeed();
189
+ }
190
+ catch (error) {
191
+ if (this.#active && this.#connectionVersion === connectionVersion) {
192
+ this.#subscription = existingSubscription;
193
+ this.#subscriptionToken = existingSubscriptionToken;
194
+ }
195
+ else {
196
+ this.#subscription = undefined;
197
+ this.#subscriptionToken = undefined;
198
+ if (existingSubscription) {
199
+ try {
200
+ await existingSubscription.unsubscribe();
201
+ }
202
+ catch {
203
+ this.#pendingUnsubscriptions.add(existingSubscription);
204
+ }
205
+ }
206
+ }
207
+ throw error;
208
+ }
209
+ const replacementSubscription = this.#subscription;
210
+ if (existingSubscription && existingSubscription !== this.#subscription) {
211
+ try {
212
+ await existingSubscription.unsubscribe();
213
+ }
214
+ catch (error) {
215
+ if (this.#active && this.#connectionVersion === connectionVersion) {
216
+ this.#subscription = existingSubscription;
217
+ this.#subscriptionToken = existingSubscriptionToken;
218
+ }
219
+ else {
220
+ this.#subscription = undefined;
221
+ this.#subscriptionToken = undefined;
222
+ this.#pendingUnsubscriptions.add(existingSubscription);
223
+ }
224
+ if (replacementSubscription) {
225
+ try {
226
+ await replacementSubscription.unsubscribe();
227
+ }
228
+ catch {
229
+ this.#pendingUnsubscriptions.add(replacementSubscription);
230
+ }
231
+ }
232
+ throw error;
233
+ }
234
+ }
235
+ }
117
236
  async #unsubscribeFromFeed() {
118
237
  const subscription = this.#subscription;
119
238
  this.#subscription = undefined;
120
- if (subscription) {
121
- await subscription.unsubscribe();
239
+ this.#subscriptionToken = undefined;
240
+ try {
241
+ if (subscription) {
242
+ await subscription.unsubscribe();
243
+ }
244
+ }
245
+ finally {
246
+ await this.#retryPendingUnsubscriptions();
247
+ }
248
+ }
249
+ async #retryPendingUnsubscriptions() {
250
+ for (const subscription of this.#pendingUnsubscriptions) {
251
+ try {
252
+ await subscription.unsubscribe();
253
+ this.#pendingUnsubscriptions.delete(subscription);
254
+ }
255
+ catch {
256
+ // Keep the subscription queued for a later cleanup attempt.
257
+ }
122
258
  }
123
259
  }
124
260
  #handleNotification(notification) {
125
- if (notification.channel !== SOCIAL_FEED_CHANNEL) {
261
+ const scope = scopeForChannel(notification.channel);
262
+ if (!scope || !this.#scopes.includes(scope)) {
126
263
  return;
127
264
  }
128
265
  parseSocialFeedEvents(notification.data).forEach((event) => {
129
- this.#listeners.forEach((listener) => listener(event));
266
+ this.#listeners.forEach((listener) => listener(event, scope));
130
267
  });
131
268
  }
132
269
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SocialRealtimeService.js","sourceRoot":"","sources":["../src/SocialRealtimeService.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebSocketState } from '@metamask/core-backend';\nimport type {\n BackendWebSocketServiceMessenger,\n ServerNotificationMessage,\n WebSocketSubscription,\n} from '@metamask/core-backend';\n\nimport type { FeedItem } from './social-types.js';\n\nexport const SOCIAL_FEED_CHANNEL = 'social.v1.feed.trending' as const;\nexport const SOCIAL_FEED_CHANNEL_TYPE = 'social.v1' as const;\n\nexport type SocialFeedEvent = {\n version: 1;\n kind: 'feed-item';\n eventId: string;\n feedItemId: string;\n revision: number;\n occurredAt: string;\n data: FeedItem;\n};\n\nexport type SocialFeedEventListener = (event: SocialFeedEvent) => void;\nexport type SocialFeedReconnectListener = () => void;\n\nexport type SocialRealtimeServiceOptions = {\n messenger: BackendWebSocketServiceMessenger;\n isEnabled?: () => boolean;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null;\n\nconst parseSocialFeedEvent = (data: unknown): SocialFeedEvent | undefined => {\n if (!isRecord(data)) {\n return undefined;\n }\n\n if (\n data.version !== 1 ||\n data.kind !== 'feed-item' ||\n typeof data.eventId !== 'string' ||\n typeof data.feedItemId !== 'string' ||\n typeof data.revision !== 'number' ||\n typeof data.occurredAt !== 'string' ||\n !isRecord(data.data)\n ) {\n return undefined;\n }\n\n return data as unknown as SocialFeedEvent;\n};\n\nconst parseSocialFeedEvents = (data: unknown): SocialFeedEvent[] => {\n const entries = Array.isArray(data) ? data : [data];\n\n return entries\n .map((entry) => parseSocialFeedEvent(entry))\n .filter((event): event is SocialFeedEvent => event !== undefined);\n};\n\n/**\n * Social realtime subscription service built on the shared backend WebSocket.\n *\n * The POC subscribes to the global feed channel. Additional Social channels\n * can be added here without creating another WebSocket connection.\n */\nexport class SocialRealtimeService {\n readonly name = 'SocialRealtimeService' as const;\n\n readonly #messenger: BackendWebSocketServiceMessenger;\n\n readonly #listeners = new Set<SocialFeedEventListener>();\n\n readonly #reconnectListeners = new Set<SocialFeedReconnectListener>();\n\n readonly #isEnabled: () => boolean;\n\n #active = false;\n\n #subscription: WebSocketSubscription | undefined;\n\n #subscriptionPromise: Promise<void> | undefined;\n\n #wasDisconnected = false;\n\n constructor({\n messenger,\n isEnabled = (): boolean => true,\n }: SocialRealtimeServiceOptions) {\n this.#messenger = messenger;\n this.#isEnabled = isEnabled;\n\n this.#messenger.subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n ({ state }: { state: WebSocketState }): void => {\n if (state === WebSocketState.DISCONNECTED) {\n this.#subscription = undefined;\n this.#wasDisconnected = true;\n }\n\n if (state === WebSocketState.CONNECTED && this.#active) {\n const isReconnect = this.#wasDisconnected;\n this.#wasDisconnected = false;\n // Subscription setup handles its own errors and must not block reconnect handling.\n // eslint-disable-next-line no-void\n void this.#subscribeToFeed();\n\n if (isReconnect) {\n this.#reconnectListeners.forEach((listener) => listener());\n }\n }\n },\n );\n }\n\n addListener(listener: SocialFeedEventListener): () => void {\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n }\n\n addReconnectListener(listener: SocialFeedReconnectListener): () => void {\n this.#reconnectListeners.add(listener);\n return () => this.#reconnectListeners.delete(listener);\n }\n\n async setActive(active: boolean): Promise<void> {\n this.#active = active && this.#isEnabled();\n\n if (!this.#active) {\n await this.#unsubscribeFromFeed();\n return;\n }\n\n await this.#subscribeToFeed();\n }\n\n async #subscribeToFeed(): Promise<void> {\n if (!this.#active || this.#subscription) {\n return;\n }\n\n while (this.#subscriptionPromise) {\n await this.#subscriptionPromise;\n\n if (!this.#active || this.#subscription) {\n return;\n }\n }\n\n const subscriptionPromise = Promise.resolve().then(\n async (): Promise<void> => {\n try {\n await this.#messenger.call('BackendWebSocketService:connect');\n\n // Each service needs its own callback and subscription lifecycle.\n const subscription = await this.#messenger.call(\n 'BackendWebSocketService:subscribe',\n {\n channels: [SOCIAL_FEED_CHANNEL],\n channelType: SOCIAL_FEED_CHANNEL_TYPE,\n callback: (notification: ServerNotificationMessage) => {\n this.#handleNotification(notification);\n },\n },\n );\n\n if (!this.#active) {\n await subscription.unsubscribe();\n return;\n }\n\n this.#subscription = subscription;\n } catch {\n this.#subscription = undefined;\n }\n },\n );\n this.#subscriptionPromise = subscriptionPromise;\n\n try {\n await subscriptionPromise;\n } finally {\n this.#subscriptionPromise = undefined;\n }\n }\n\n async #unsubscribeFromFeed(): Promise<void> {\n const subscription = this.#subscription;\n this.#subscription = undefined;\n\n if (subscription) {\n await subscription.unsubscribe();\n }\n }\n\n #handleNotification(notification: ServerNotificationMessage): void {\n if (notification.channel !== SOCIAL_FEED_CHANNEL) {\n return;\n }\n\n parseSocialFeedEvents(notification.data).forEach((event) => {\n this.#listeners.forEach((listener) => listener(event));\n });\n }\n}\n"]}
1
+ {"version":3,"file":"SocialRealtimeService.js","sourceRoot":"","sources":["../src/SocialRealtimeService.ts"],"names":[],"mappings":"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","sourcesContent":["import { WebSocketState } from '@metamask/core-backend';\nimport type {\n BackendWebSocketServiceMessenger,\n ServerNotificationMessage,\n WebSocketSubscription,\n} from '@metamask/core-backend';\n\nimport { parseSocialRealtimeFeedItem } from './structs.js';\nimport type { SocialRealtimeFeedItem } from './structs.js';\n\nexport const SOCIAL_FEED_CHANNELS = {\n all: 'social.v1.feed.all',\n trending: 'social.v1.feed.trending',\n} as const;\n\nexport type SocialFeedRealtimeScope = keyof typeof SOCIAL_FEED_CHANNELS;\n\nexport const SOCIAL_FEED_CHANNEL_TYPE = 'social.v1' as const;\n\nexport type SocialFeedEvent = {\n version: 1;\n kind: 'feed-item';\n eventId: string;\n feedItemId: string;\n revision: number;\n occurredAt: string;\n data: SocialRealtimeFeedItem;\n};\n\nexport type SocialFeedEventListener = (\n event: SocialFeedEvent,\n scope: SocialFeedRealtimeScope,\n) => void;\nexport type SocialFeedReconnectListener = () => void;\n\nexport type SocialRealtimeServiceOptions = {\n messenger: BackendWebSocketServiceMessenger;\n scopes: readonly SocialFeedRealtimeScope[];\n isEnabled?: () => boolean;\n};\n\nconst isRecord = (value: unknown): value is Record<string, unknown> =>\n typeof value === 'object' && value !== null;\n\nconst normalizeScopes = (\n scopes: readonly SocialFeedRealtimeScope[],\n): SocialFeedRealtimeScope[] => {\n const normalized = [...new Set(scopes)];\n if (normalized.length === 0) {\n throw new Error('At least one Social feed scope is required');\n }\n return normalized;\n};\n\nconst scopeForChannel = (\n channel: string,\n): SocialFeedRealtimeScope | undefined =>\n (Object.entries(SOCIAL_FEED_CHANNELS).find(\n ([, value]) => value === channel,\n )?.[0] as SocialFeedRealtimeScope | undefined) ?? undefined;\n\nconst parseSocialFeedEvent = (data: unknown): SocialFeedEvent | undefined => {\n if (!isRecord(data)) {\n return undefined;\n }\n\n const feedItem = parseSocialRealtimeFeedItem(data.data);\n if (\n data.version !== 1 ||\n data.kind !== 'feed-item' ||\n typeof data.eventId !== 'string' ||\n typeof data.feedItemId !== 'string' ||\n typeof data.revision !== 'number' ||\n typeof data.occurredAt !== 'string' ||\n feedItem === undefined\n ) {\n return undefined;\n }\n\n return { ...data, data: feedItem } as unknown as SocialFeedEvent;\n};\n\nconst parseSocialFeedEvents = (data: unknown): SocialFeedEvent[] => {\n const entries = Array.isArray(data) ? data : [data];\n\n return entries\n .map((entry) => parseSocialFeedEvent(entry))\n .filter((event): event is SocialFeedEvent => event !== undefined);\n};\n\n/**\n * Social realtime subscription service built on the shared backend WebSocket.\n *\n * Clients explicitly select one or more global feed scopes. Additional Social\n * channels can be added here without creating another WebSocket connection.\n */\nexport class SocialRealtimeService {\n readonly name = 'SocialRealtimeService' as const;\n\n readonly #messenger: BackendWebSocketServiceMessenger;\n\n readonly #listeners = new Set<SocialFeedEventListener>();\n\n readonly #reconnectListeners = new Set<SocialFeedReconnectListener>();\n\n readonly #isEnabled: () => boolean;\n\n #scopes: SocialFeedRealtimeScope[];\n\n #scopeUpdatePromise: Promise<void> | undefined;\n\n #active = false;\n\n #subscription: WebSocketSubscription | undefined;\n\n #subscriptionToken: symbol | undefined;\n\n #subscriptionPromise: Promise<void> | undefined;\n\n readonly #pendingUnsubscriptions = new Set<WebSocketSubscription>();\n\n #connectionVersion = 0;\n\n #wasDisconnected = false;\n\n constructor({\n messenger,\n scopes,\n isEnabled = (): boolean => true,\n }: SocialRealtimeServiceOptions) {\n this.#messenger = messenger;\n this.#scopes = normalizeScopes(scopes);\n this.#isEnabled = isEnabled;\n\n this.#messenger.subscribe(\n 'BackendWebSocketService:connectionStateChanged',\n ({ state }: { state: WebSocketState }): void => {\n if (state === WebSocketState.DISCONNECTED) {\n this.#connectionVersion += 1;\n this.#subscription = undefined;\n this.#subscriptionToken = undefined;\n this.#wasDisconnected = true;\n }\n\n if (state === WebSocketState.CONNECTED && this.#active) {\n const isReconnect = this.#wasDisconnected;\n this.#wasDisconnected = false;\n // eslint-disable-next-line no-void\n void this.#subscribeToFeed()\n .then(() => {\n if (isReconnect) {\n this.#reconnectListeners.forEach((listener) => listener());\n }\n })\n .catch(() => undefined);\n }\n },\n );\n }\n\n addListener(listener: SocialFeedEventListener): () => void {\n this.#listeners.add(listener);\n return () => this.#listeners.delete(listener);\n }\n\n addReconnectListener(listener: SocialFeedReconnectListener): () => void {\n this.#reconnectListeners.add(listener);\n return () => this.#reconnectListeners.delete(listener);\n }\n\n async setScopes(scopes: readonly SocialFeedRealtimeScope[]): Promise<void> {\n const normalizedScopes = normalizeScopes(scopes);\n\n const scopeUpdate = this.#scopeUpdatePromise\n ? this.#scopeUpdatePromise\n .catch(() => undefined)\n .then(() => this.#applyScopes(normalizedScopes))\n : this.#applyScopes(normalizedScopes);\n this.#scopeUpdatePromise = scopeUpdate;\n\n try {\n await scopeUpdate;\n } finally {\n if (this.#scopeUpdatePromise === scopeUpdate) {\n this.#scopeUpdatePromise = Promise.resolve();\n }\n }\n }\n\n async #applyScopes(\n normalizedScopes: SocialFeedRealtimeScope[],\n ): Promise<void> {\n if (!this.#active) {\n this.#scopes = normalizedScopes;\n return;\n }\n\n const previousScopes = this.#scopes;\n const connectionVersion = this.#connectionVersion;\n this.#scopes = normalizedScopes;\n\n try {\n await this.#resubscribeToFeed();\n } catch (error) {\n if (\n this.#active &&\n this.#connectionVersion === connectionVersion &&\n this.#subscription\n ) {\n this.#scopes = previousScopes;\n }\n throw error;\n }\n }\n\n async setActive(active: boolean): Promise<void> {\n this.#active = active && this.#isEnabled();\n\n if (!this.#active) {\n await this.#unsubscribeFromFeed();\n return;\n }\n\n await this.#retryPendingUnsubscriptions();\n await this.#subscribeToFeed();\n }\n\n async #subscribeToFeed(): Promise<void> {\n if (!this.#active || this.#subscription) {\n return;\n }\n\n while (this.#subscriptionPromise) {\n await this.#subscriptionPromise;\n\n if (!this.#active || this.#subscription) {\n return;\n }\n }\n\n const subscriptionPromise = Promise.resolve().then(\n async (): Promise<void> => {\n await this.#messenger.call('BackendWebSocketService:connect');\n\n const subscriptionToken = Symbol('social-feed-subscription');\n\n // Each service needs its own callback and subscription lifecycle.\n const subscription = await this.#messenger.call(\n 'BackendWebSocketService:subscribe',\n {\n channels: this.#scopes.map((scope) => SOCIAL_FEED_CHANNELS[scope]),\n channelType: SOCIAL_FEED_CHANNEL_TYPE,\n callback: (notification: ServerNotificationMessage) => {\n if (this.#subscriptionToken !== subscriptionToken) {\n return;\n }\n this.#handleNotification(notification);\n },\n },\n );\n\n if (!this.#active) {\n await subscription.unsubscribe();\n return;\n }\n\n this.#subscription = subscription;\n this.#subscriptionToken = subscriptionToken;\n },\n );\n this.#subscriptionPromise = subscriptionPromise;\n\n try {\n await subscriptionPromise;\n } finally {\n this.#subscriptionPromise = undefined;\n }\n }\n\n async #resubscribeToFeed(): Promise<void> {\n while (this.#subscriptionPromise) {\n await this.#subscriptionPromise;\n }\n\n await this.#retryPendingUnsubscriptions();\n\n const existingSubscription = this.#subscription;\n const existingSubscriptionToken = this.#subscriptionToken;\n const connectionVersion = this.#connectionVersion;\n this.#subscription = undefined;\n\n try {\n await this.#subscribeToFeed();\n } catch (error) {\n if (this.#active && this.#connectionVersion === connectionVersion) {\n this.#subscription = existingSubscription;\n this.#subscriptionToken = existingSubscriptionToken;\n } else {\n this.#subscription = undefined;\n this.#subscriptionToken = undefined;\n\n if (existingSubscription) {\n try {\n await existingSubscription.unsubscribe();\n } catch {\n this.#pendingUnsubscriptions.add(existingSubscription);\n }\n }\n }\n throw error;\n }\n\n const replacementSubscription = this.#subscription as\n | WebSocketSubscription\n | undefined;\n if (existingSubscription && existingSubscription !== this.#subscription) {\n try {\n await existingSubscription.unsubscribe();\n } catch (error) {\n if (this.#active && this.#connectionVersion === connectionVersion) {\n this.#subscription = existingSubscription;\n this.#subscriptionToken = existingSubscriptionToken;\n } else {\n this.#subscription = undefined;\n this.#subscriptionToken = undefined;\n this.#pendingUnsubscriptions.add(existingSubscription);\n }\n\n if (replacementSubscription) {\n try {\n await replacementSubscription.unsubscribe();\n } catch {\n this.#pendingUnsubscriptions.add(replacementSubscription);\n }\n }\n\n throw error;\n }\n }\n }\n\n async #unsubscribeFromFeed(): Promise<void> {\n const subscription = this.#subscription;\n this.#subscription = undefined;\n this.#subscriptionToken = undefined;\n\n try {\n if (subscription) {\n await subscription.unsubscribe();\n }\n } finally {\n await this.#retryPendingUnsubscriptions();\n }\n }\n\n async #retryPendingUnsubscriptions(): Promise<void> {\n for (const subscription of this.#pendingUnsubscriptions) {\n try {\n await subscription.unsubscribe();\n this.#pendingUnsubscriptions.delete(subscription);\n } catch {\n // Keep the subscription queued for a later cleanup attempt.\n }\n }\n }\n\n #handleNotification(notification: ServerNotificationMessage): void {\n const scope = scopeForChannel(notification.channel);\n if (!scope || !this.#scopes.includes(scope)) {\n return;\n }\n\n parseSocialFeedEvents(notification.data).forEach((event) => {\n this.#listeners.forEach((listener) => listener(event, scope));\n });\n }\n}\n"]}
@@ -20,6 +20,9 @@ export type SocialServiceFetchLeaderboardAction = {
20
20
  *
21
21
  * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.
22
22
  *
23
+ * `profile.createdAt` is optional. When present it is an ISO-8601 timestamp
24
+ * for when the social-api profile row was inserted.
25
+ *
23
26
  * @param options - Options bag.
24
27
  * @param options.addressOrId - Wallet address or Clicker profile ID.
25
28
  * @returns The trader profile response.
@@ -120,7 +123,8 @@ export type SocialServiceFetchPositionByIdAction = {
120
123
  * `pagination.newerCursor` as `newerThan` to fetch newer items.
121
124
  *
122
125
  * @param options - Options bag.
123
- * @param options.scope - `following` (default) or `leaderboard`.
126
+ * @param options.scope - `following` (default), `leaderboard`, `all`, or
127
+ * `trending`.
124
128
  * @param options.chains - Filter by one or more chains.
125
129
  * @param options.limit - Number of results per page.
126
130
  * @param options.olderThan - Cursor for older items (scroll down).
@@ -237,6 +241,26 @@ export type SocialServiceCreateSwapCommentAction = {
237
241
  type: `SocialService:createSwapComment`;
238
242
  handler: SocialService['createSwapComment'];
239
243
  };
244
+ /**
245
+ * Records that the current user is copying a trade from a social post, so
246
+ * the copy can be detected and attributed to the post's author.
247
+ *
248
+ * Calls `POST ${baseUrl}/copy-trade-intents`. Send swaps before submission
249
+ * with the Bridge quote id, and perps right after submission with the
250
+ * returned order id. The endpoint is idempotent per profile, origin, and
251
+ * execution id: it answers 201 for a new intent and 200 with the existing
252
+ * one on a retry.
253
+ *
254
+ * @param options - Options bag.
255
+ * @param options.origin - Comment the trade was copied from.
256
+ * @param options.copierAccount - CAIP-10 account placing the trade.
257
+ * @param options.execution - Swap quote id or perps order id.
258
+ * @returns The created or existing copy-trade intent.
259
+ */
260
+ export type SocialServiceCreateCopyTradeIntentAction = {
261
+ type: `SocialService:createCopyTradeIntent`;
262
+ handler: SocialService['createCopyTradeIntent'];
263
+ };
240
264
  /**
241
265
  * Fetches the list of traders the current user is following.
242
266
  *
@@ -392,5 +416,5 @@ export type SocialServiceFetchBlockedContentAction = {
392
416
  /**
393
417
  * Union of all SocialService action types.
394
418
  */
395
- export type SocialServiceMethodActions = SocialServiceFetchLeaderboardAction | SocialServiceFetchTraderProfileAction | SocialServiceFetchOpenPositionsAction | SocialServiceFetchClosedPositionsAction | SocialServiceFetchFollowersAction | SocialServiceFetchTraderFollowingAction | SocialServiceFetchPositionByIdAction | SocialServiceFetchFeedAction | SocialServiceFetchTraderFeedAction | SocialServiceFetchTokenFeedAction | SocialServiceReactToCommentAction | SocialServiceRemoveCommentReactionAction | SocialServiceCreateSwapCommentAction | SocialServiceFetchFollowingAction | SocialServiceFetchMyFollowingAction | SocialServiceFetchMyFollowersAction | SocialServiceFollowAction | SocialServiceUnfollowAction | SocialServiceOptOutOfLeaderboardAction | SocialServiceOptInToLeaderboardAction | SocialServiceRefreshNotificationPreferencesCacheAction | SocialServiceBlockAction | SocialServiceFetchBlockedProfilesAction | SocialServiceFetchBlockedContentAction;
419
+ export type SocialServiceMethodActions = SocialServiceFetchLeaderboardAction | SocialServiceFetchTraderProfileAction | SocialServiceFetchOpenPositionsAction | SocialServiceFetchClosedPositionsAction | SocialServiceFetchFollowersAction | SocialServiceFetchTraderFollowingAction | SocialServiceFetchPositionByIdAction | SocialServiceFetchFeedAction | SocialServiceFetchTraderFeedAction | SocialServiceFetchTokenFeedAction | SocialServiceReactToCommentAction | SocialServiceRemoveCommentReactionAction | SocialServiceCreateSwapCommentAction | SocialServiceCreateCopyTradeIntentAction | SocialServiceFetchFollowingAction | SocialServiceFetchMyFollowingAction | SocialServiceFetchMyFollowersAction | SocialServiceFollowAction | SocialServiceUnfollowAction | SocialServiceOptOutOfLeaderboardAction | SocialServiceOptInToLeaderboardAction | SocialServiceRefreshNotificationPreferencesCacheAction | SocialServiceBlockAction | SocialServiceFetchBlockedProfilesAction | SocialServiceFetchBlockedContentAction;
396
420
  //# sourceMappingURL=SocialService-method-action-types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"SocialService-method-action-types.d.ts","sourceRoot":"","sources":["../src/SocialService-method-action-types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"SocialService-method-action-types.d.ts","sourceRoot":"","sources":["../src/SocialService-method-action-types.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"SocialService-method-action-types.js","sourceRoot":"","sources":["../src/SocialService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { SocialService } from './SocialService.js';\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 */\nexport type SocialServiceFetchLeaderboardAction = {\n type: `SocialService:fetchLeaderboard`;\n handler: SocialService['fetchLeaderboard'];\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 */\nexport type SocialServiceFetchTraderProfileAction = {\n type: `SocialService:fetchTraderProfile`;\n handler: SocialService['fetchTraderProfile'];\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 */\nexport type SocialServiceFetchOpenPositionsAction = {\n type: `SocialService:fetchOpenPositions`;\n handler: SocialService['fetchOpenPositions'];\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 */\nexport type SocialServiceFetchClosedPositionsAction = {\n type: `SocialService:fetchClosedPositions`;\n handler: SocialService['fetchClosedPositions'];\n};\n\n/**\n * Fetches a trader's MetaMask followers.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/followers`. Pass\n * `mutuals: true` to append `?mutuals=true` (profiles that follow both this\n * trader and the authenticated user; `count` is the mutual total). Requires a\n * bearer token; the trader is identified by `addressOrId`, not the JWT\n * subject (see {@link fetchMyFollowers} for the current user's inbound list).\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @param options.mutuals - When true, request mutual followers only.\n * @returns The followers response.\n */\nexport type SocialServiceFetchFollowersAction = {\n type: `SocialService:fetchFollowers`;\n handler: SocialService['fetchFollowers'];\n};\n\n/**\n * Fetches the list of traders a profile follows.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/following`. Requires a bearer\n * token; the trader is identified by `addressOrId`, not the JWT subject (see\n * {@link fetchFollowing} for the current user's outbound list).\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @returns The following response.\n */\nexport type SocialServiceFetchTraderFollowingAction = {\n type: `SocialService:fetchTraderFollowing`;\n handler: SocialService['fetchTraderFollowing'];\n};\n\n/**\n * Fetches a single position by its unique ID.\n *\n * Calls `GET ${baseUrl}/traders/position/${positionId}`.\n *\n * @param options - Options bag.\n * @param options.positionId - Unique position ID (UUID).\n * @returns The position.\n */\nexport type SocialServiceFetchPositionByIdAction = {\n type: `SocialService:fetchPositionById`;\n handler: SocialService['fetchPositionById'];\n};\n\n/**\n * Fetches a page of the trader-activity feed.\n *\n * Calls `GET ${baseUrl}/feed`. For the `following` scope the current user is\n * identified server-side from the JWT sub claim carried in the Authorization\n * header; the `leaderboard` scope is generic and shared by all users.\n *\n * Cursor pagination supports infinite scroll: pass `pagination.olderCursor`\n * from a prior response back as `olderThan` to load older items, and\n * `pagination.newerCursor` as `newerThan` to fetch newer items.\n *\n * @param options - Options bag.\n * @param options.scope - `following` (default) or `leaderboard`.\n * @param options.chains - Filter by one or more chains.\n * @param options.limit - Number of results per page.\n * @param options.olderThan - Cursor for older items (scroll down).\n * @param options.newerThan - Cursor for newer items (refresh).\n * @returns The feed response with items and pagination cursors.\n */\nexport type SocialServiceFetchFeedAction = {\n type: `SocialService:fetchFeed`;\n handler: SocialService['fetchFeed'];\n};\n\n/**\n * Fetches a page of one trader's activity as feed items.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/feed`. Unlike {@link fetchFeed},\n * this is scoped to a single profile (open and closed positions in the feed)\n * and does not accept `scope` or `chains`. Set `commentedOnly` to only return\n * positions that carry an author comment.\n *\n * The route is public, but the Authorization header is still sent so the\n * social-api can hydrate `authorComment.engagement.userReaction` for the\n * signed-in viewer.\n *\n * Cursor pagination supports infinite scroll: pass `pagination.olderCursor`\n * from a prior response back as `olderThan` to load older items, and\n * `pagination.newerCursor` as `newerThan` to fetch newer items.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @param options.commentedOnly - When true, only positions with a comment.\n * @param options.limit - Number of results per page.\n * @param options.olderThan - Cursor for older items (scroll down).\n * @param options.newerThan - Cursor for newer items (refresh).\n * @returns The feed response with items and pagination cursors.\n */\nexport type SocialServiceFetchTraderFeedAction = {\n type: `SocialService:fetchTraderFeed`;\n handler: SocialService['fetchTraderFeed'];\n};\n\n/**\n * Fetches a page of positions in one token, most recently traded first.\n *\n * Calls `GET ${baseUrl}/tokens/${chain}/${contractAddress}/feed`. Unlike\n * {@link fetchFeed}, this is scoped to a single token and does not accept\n * `scope` or `chains`. Omit `status` to include both open and recently\n * closed positions.\n *\n * The route is public, but the Authorization header is still sent so the\n * social-api can hydrate `authorComment.engagement.userReaction` for the\n * signed-in viewer.\n *\n * Cursor pagination supports infinite scroll: pass `pagination.olderCursor`\n * from a prior response back as `olderThan` to load older items, and\n * `pagination.newerCursor` as `newerThan` to fetch newer items.\n *\n * @param options - Options bag.\n * @param options.chain - Chain name where the token is deployed (`TokenFeedChain`).\n * @param options.contractAddress - Token contract address.\n * @param options.status - `open`, `closed`, or omit for both.\n * @param options.limit - Number of results per page.\n * @param options.olderThan - Cursor for older items (scroll down).\n * @param options.newerThan - Cursor for newer items (refresh).\n * @returns The feed response with items and pagination cursors.\n */\nexport type SocialServiceFetchTokenFeedAction = {\n type: `SocialService:fetchTokenFeed`;\n handler: SocialService['fetchTokenFeed'];\n};\n\n/**\n * Adds or replaces the current user's reaction on a swap comment (Call).\n *\n * Calls `PUT ${baseUrl}/swap-comment/${commentId}/reaction`. One emotion per\n * user per comment: a later PUT replaces the previous emotion.\n *\n * @param options - Options bag.\n * @param options.commentId - `authorComment.uid` from a feed item.\n * @param options.emotion - Emoji or short code to store.\n * @returns Refreshed per-emotion counts and the caller's `userReaction`.\n */\nexport type SocialServiceReactToCommentAction = {\n type: `SocialService:reactToComment`;\n handler: SocialService['reactToComment'];\n};\n\n/**\n * Removes the current user's reaction on a swap comment (Call).\n *\n * Calls `DELETE ${baseUrl}/swap-comment/${commentId}/reaction`. Idempotent\n * when the caller has never reacted.\n *\n * @param options - Options bag.\n * @param options.commentId - `authorComment.uid` from a feed item.\n * @returns Refreshed per-emotion counts and a null `userReaction`.\n */\nexport type SocialServiceRemoveCommentReactionAction = {\n type: `SocialService:removeCommentReaction`;\n handler: SocialService['removeCommentReaction'];\n};\n\n/**\n * Creates an author Call (user post) on one of the current user's swaps.\n *\n * Calls `POST ${baseUrl}/swap-comments`. Identify the swap with\n * `positionUid` (the `positionId` of a feed item or position) or, for a\n * trade too recent to be indexed, `tradeInFlight`. Provide exactly one of\n * those two fields.\n *\n * @param options - Options bag.\n * @param options.commentText - Message body of the post. May include a\n * `https://static.klipy.com/...gif` file URL; social-api rejects other links.\n * @param options.source - Free-form origin label stored on the comment.\n * @param options.positionUid - Position UUID (`positionId` / feed item id).\n * @param options.tradeInFlight - Hash, chain, and token of a swap in flight.\n * @returns The created swap comment.\n */\nexport type SocialServiceCreateSwapCommentAction = {\n type: `SocialService:createSwapComment`;\n handler: SocialService['createSwapComment'];\n};\n\n/**\n * Fetches the list of traders the current user is following.\n *\n * Calls `GET ${baseUrl}/users/me/following`. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * Prefer {@link fetchMyFollowing} in new code (pairs with\n * {@link fetchMyFollowers}). This method is unchanged and remains the\n * `/users/me/following` read.\n *\n * @returns The following response.\n */\nexport type SocialServiceFetchFollowingAction = {\n type: `SocialService:fetchFollowing`;\n handler: SocialService['fetchFollowing'];\n};\n\n/**\n * Fetches the list of traders the current user is following.\n *\n * Alias of {@link fetchFollowing}. Calls `GET ${baseUrl}/users/me/following`.\n * Preferred name in new code so `/users/me` reads are both `fetchMy*`.\n *\n * @returns The following response.\n */\nexport type SocialServiceFetchMyFollowingAction = {\n type: `SocialService:fetchMyFollowing`;\n handler: SocialService['fetchMyFollowing'];\n};\n\n/**\n * Fetches the list of traders following the current user.\n *\n * Calls `GET ${baseUrl}/users/me/followers`. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @returns The followers response.\n */\nexport type SocialServiceFetchMyFollowersAction = {\n type: `SocialService:fetchMyFollowers`;\n handler: SocialService['fetchMyFollowers'];\n};\n\n/**\n * Follows one or more traders on behalf of the current user.\n *\n * Calls `PUT ${baseUrl}/users/me/follows`. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.targets - Array of wallet addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\nexport type SocialServiceFollowAction = {\n type: `SocialService:follow`;\n handler: SocialService['follow'];\n};\n\n/**\n * Unfollows one or more traders on behalf of the current user.\n *\n * Calls `DELETE ${baseUrl}/users/me/follows?targets=...`. Targets are sent\n * as query params because Fastify does not parse request bodies on DELETE\n * requests per RFC 9110. The caller is identified server-side from the JWT\n * sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.targets - Array of wallet addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\nexport type SocialServiceUnfollowAction = {\n type: `SocialService:unfollow`;\n handler: SocialService['unfollow'];\n};\n\n/**\n * Opts the current user out of the PnL leaderboard.\n */\nexport type SocialServiceOptOutOfLeaderboardAction = {\n type: `SocialService:optOutOfLeaderboard`;\n handler: SocialService['optOutOfLeaderboard'];\n};\n\n/**\n * Opts the current user back into the PnL leaderboard.\n */\nexport type SocialServiceOptInToLeaderboardAction = {\n type: `SocialService:optInToLeaderboard`;\n handler: SocialService['optInToLeaderboard'];\n};\n\n/**\n * Asks the social-api to refresh its cached copy of the current user's\n * notification preferences.\n *\n * Calls `POST ${baseUrl}/notifications/preferences/cache-refresh`. The caller\n * is identified server-side from the JWT sub claim carried in the\n * Authorization header, so it can only ever refresh its own entry.\n *\n * The client calls this immediately after writing a preference change to\n * Authenticated User Storage (AUS), which is the source of truth. The social\n * api re-reads from AUS and repopulates its cache so the change is honoured\n * near-instantly rather than after the cache TTL lapses. It is a pure\n * optimisation on top of that bounded TTL: the write has already succeeded by\n * the time this runs, so callers should treat it as best-effort and must not\n * roll back the AUS write if it fails.\n */\nexport type SocialServiceRefreshNotificationPreferencesCacheAction = {\n type: `SocialService:refreshNotificationPreferencesCache`;\n handler: SocialService['refreshNotificationPreferencesCache'];\n};\n\n/**\n * Blocks a trader, swap comment, or reply for the current user.\n *\n * Calls `PUT ${baseUrl}/moderation/block`. Provide exactly one of\n * `profileId`, `commentId`, or `replyId`. Blocking the same target again\n * replaces `reason` when one is given. The caller is identified server-side\n * from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag. Exactly one target, plus an optional reason.\n * @param options.profileId - Profile id (UUID) of the trader to block.\n * @param options.commentId - Swap comment to block.\n * @param options.replyId - Comment reply to block.\n * @param options.reason - Free-form reason stored on the block.\n */\nexport type SocialServiceBlockAction = {\n type: `SocialService:block`;\n handler: SocialService['block'];\n};\n\n/**\n * Fetches traders the current user has blocked.\n *\n * Calls `GET ${baseUrl}/moderation/blocks/profiles`. Results are most\n * recently blocked first, 250 per page. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.cursor - Cursor from the previous page. Omit for the first page.\n * @returns The blocked profiles page.\n */\nexport type SocialServiceFetchBlockedProfilesAction = {\n type: `SocialService:fetchBlockedProfiles`;\n handler: SocialService['fetchBlockedProfiles'];\n};\n\n/**\n * Fetches comments and replies the current user has blocked.\n *\n * Calls `GET ${baseUrl}/moderation/blocks/content`. Results are most\n * recently blocked first, 250 per page. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.cursor - Cursor from the previous page. Omit for the first page.\n * @returns The blocked content page.\n */\nexport type SocialServiceFetchBlockedContentAction = {\n type: `SocialService:fetchBlockedContent`;\n handler: SocialService['fetchBlockedContent'];\n};\n\n/**\n * Union of all SocialService action types.\n */\nexport type SocialServiceMethodActions =\n | SocialServiceFetchLeaderboardAction\n | SocialServiceFetchTraderProfileAction\n | SocialServiceFetchOpenPositionsAction\n | SocialServiceFetchClosedPositionsAction\n | SocialServiceFetchFollowersAction\n | SocialServiceFetchTraderFollowingAction\n | SocialServiceFetchPositionByIdAction\n | SocialServiceFetchFeedAction\n | SocialServiceFetchTraderFeedAction\n | SocialServiceFetchTokenFeedAction\n | SocialServiceReactToCommentAction\n | SocialServiceRemoveCommentReactionAction\n | SocialServiceCreateSwapCommentAction\n | SocialServiceFetchFollowingAction\n | SocialServiceFetchMyFollowingAction\n | SocialServiceFetchMyFollowersAction\n | SocialServiceFollowAction\n | SocialServiceUnfollowAction\n | SocialServiceOptOutOfLeaderboardAction\n | SocialServiceOptInToLeaderboardAction\n | SocialServiceRefreshNotificationPreferencesCacheAction\n | SocialServiceBlockAction\n | SocialServiceFetchBlockedProfilesAction\n | SocialServiceFetchBlockedContentAction;\n"]}
1
+ {"version":3,"file":"SocialService-method-action-types.js","sourceRoot":"","sources":["../src/SocialService-method-action-types.ts"],"names":[],"mappings":"AAAA;;;GAGG","sourcesContent":["/**\n * This file is auto generated.\n * Do not edit manually.\n */\n\nimport type { SocialService } from './SocialService.js';\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 */\nexport type SocialServiceFetchLeaderboardAction = {\n type: `SocialService:fetchLeaderboard`;\n handler: SocialService['fetchLeaderboard'];\n};\n\n/**\n * Fetches a trader's profile by address or profile ID.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/profile`.\n *\n * `profile.createdAt` is optional. When present it is an ISO-8601 timestamp\n * for when the social-api profile row was inserted.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @returns The trader profile response.\n */\nexport type SocialServiceFetchTraderProfileAction = {\n type: `SocialService:fetchTraderProfile`;\n handler: SocialService['fetchTraderProfile'];\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 */\nexport type SocialServiceFetchOpenPositionsAction = {\n type: `SocialService:fetchOpenPositions`;\n handler: SocialService['fetchOpenPositions'];\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 */\nexport type SocialServiceFetchClosedPositionsAction = {\n type: `SocialService:fetchClosedPositions`;\n handler: SocialService['fetchClosedPositions'];\n};\n\n/**\n * Fetches a trader's MetaMask followers.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/followers`. Pass\n * `mutuals: true` to append `?mutuals=true` (profiles that follow both this\n * trader and the authenticated user; `count` is the mutual total). Requires a\n * bearer token; the trader is identified by `addressOrId`, not the JWT\n * subject (see {@link fetchMyFollowers} for the current user's inbound list).\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @param options.mutuals - When true, request mutual followers only.\n * @returns The followers response.\n */\nexport type SocialServiceFetchFollowersAction = {\n type: `SocialService:fetchFollowers`;\n handler: SocialService['fetchFollowers'];\n};\n\n/**\n * Fetches the list of traders a profile follows.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/following`. Requires a bearer\n * token; the trader is identified by `addressOrId`, not the JWT subject (see\n * {@link fetchFollowing} for the current user's outbound list).\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @returns The following response.\n */\nexport type SocialServiceFetchTraderFollowingAction = {\n type: `SocialService:fetchTraderFollowing`;\n handler: SocialService['fetchTraderFollowing'];\n};\n\n/**\n * Fetches a single position by its unique ID.\n *\n * Calls `GET ${baseUrl}/traders/position/${positionId}`.\n *\n * @param options - Options bag.\n * @param options.positionId - Unique position ID (UUID).\n * @returns The position.\n */\nexport type SocialServiceFetchPositionByIdAction = {\n type: `SocialService:fetchPositionById`;\n handler: SocialService['fetchPositionById'];\n};\n\n/**\n * Fetches a page of the trader-activity feed.\n *\n * Calls `GET ${baseUrl}/feed`. For the `following` scope the current user is\n * identified server-side from the JWT sub claim carried in the Authorization\n * header; the `leaderboard` scope is generic and shared by all users.\n *\n * Cursor pagination supports infinite scroll: pass `pagination.olderCursor`\n * from a prior response back as `olderThan` to load older items, and\n * `pagination.newerCursor` as `newerThan` to fetch newer items.\n *\n * @param options - Options bag.\n * @param options.scope - `following` (default), `leaderboard`, `all`, or\n * `trending`.\n * @param options.chains - Filter by one or more chains.\n * @param options.limit - Number of results per page.\n * @param options.olderThan - Cursor for older items (scroll down).\n * @param options.newerThan - Cursor for newer items (refresh).\n * @returns The feed response with items and pagination cursors.\n */\nexport type SocialServiceFetchFeedAction = {\n type: `SocialService:fetchFeed`;\n handler: SocialService['fetchFeed'];\n};\n\n/**\n * Fetches a page of one trader's activity as feed items.\n *\n * Calls `GET ${baseUrl}/traders/${addressOrId}/feed`. Unlike {@link fetchFeed},\n * this is scoped to a single profile (open and closed positions in the feed)\n * and does not accept `scope` or `chains`. Set `commentedOnly` to only return\n * positions that carry an author comment.\n *\n * The route is public, but the Authorization header is still sent so the\n * social-api can hydrate `authorComment.engagement.userReaction` for the\n * signed-in viewer.\n *\n * Cursor pagination supports infinite scroll: pass `pagination.olderCursor`\n * from a prior response back as `olderThan` to load older items, and\n * `pagination.newerCursor` as `newerThan` to fetch newer items.\n *\n * @param options - Options bag.\n * @param options.addressOrId - Wallet address or Clicker profile ID.\n * @param options.commentedOnly - When true, only positions with a comment.\n * @param options.limit - Number of results per page.\n * @param options.olderThan - Cursor for older items (scroll down).\n * @param options.newerThan - Cursor for newer items (refresh).\n * @returns The feed response with items and pagination cursors.\n */\nexport type SocialServiceFetchTraderFeedAction = {\n type: `SocialService:fetchTraderFeed`;\n handler: SocialService['fetchTraderFeed'];\n};\n\n/**\n * Fetches a page of positions in one token, most recently traded first.\n *\n * Calls `GET ${baseUrl}/tokens/${chain}/${contractAddress}/feed`. Unlike\n * {@link fetchFeed}, this is scoped to a single token and does not accept\n * `scope` or `chains`. Omit `status` to include both open and recently\n * closed positions.\n *\n * The route is public, but the Authorization header is still sent so the\n * social-api can hydrate `authorComment.engagement.userReaction` for the\n * signed-in viewer.\n *\n * Cursor pagination supports infinite scroll: pass `pagination.olderCursor`\n * from a prior response back as `olderThan` to load older items, and\n * `pagination.newerCursor` as `newerThan` to fetch newer items.\n *\n * @param options - Options bag.\n * @param options.chain - Chain name where the token is deployed (`TokenFeedChain`).\n * @param options.contractAddress - Token contract address.\n * @param options.status - `open`, `closed`, or omit for both.\n * @param options.limit - Number of results per page.\n * @param options.olderThan - Cursor for older items (scroll down).\n * @param options.newerThan - Cursor for newer items (refresh).\n * @returns The feed response with items and pagination cursors.\n */\nexport type SocialServiceFetchTokenFeedAction = {\n type: `SocialService:fetchTokenFeed`;\n handler: SocialService['fetchTokenFeed'];\n};\n\n/**\n * Adds or replaces the current user's reaction on a swap comment (Call).\n *\n * Calls `PUT ${baseUrl}/swap-comment/${commentId}/reaction`. One emotion per\n * user per comment: a later PUT replaces the previous emotion.\n *\n * @param options - Options bag.\n * @param options.commentId - `authorComment.uid` from a feed item.\n * @param options.emotion - Emoji or short code to store.\n * @returns Refreshed per-emotion counts and the caller's `userReaction`.\n */\nexport type SocialServiceReactToCommentAction = {\n type: `SocialService:reactToComment`;\n handler: SocialService['reactToComment'];\n};\n\n/**\n * Removes the current user's reaction on a swap comment (Call).\n *\n * Calls `DELETE ${baseUrl}/swap-comment/${commentId}/reaction`. Idempotent\n * when the caller has never reacted.\n *\n * @param options - Options bag.\n * @param options.commentId - `authorComment.uid` from a feed item.\n * @returns Refreshed per-emotion counts and a null `userReaction`.\n */\nexport type SocialServiceRemoveCommentReactionAction = {\n type: `SocialService:removeCommentReaction`;\n handler: SocialService['removeCommentReaction'];\n};\n\n/**\n * Creates an author Call (user post) on one of the current user's swaps.\n *\n * Calls `POST ${baseUrl}/swap-comments`. Identify the swap with\n * `positionUid` (the `positionId` of a feed item or position) or, for a\n * trade too recent to be indexed, `tradeInFlight`. Provide exactly one of\n * those two fields.\n *\n * @param options - Options bag.\n * @param options.commentText - Message body of the post. May include a\n * `https://static.klipy.com/...gif` file URL; social-api rejects other links.\n * @param options.source - Free-form origin label stored on the comment.\n * @param options.positionUid - Position UUID (`positionId` / feed item id).\n * @param options.tradeInFlight - Hash, chain, and token of a swap in flight.\n * @returns The created swap comment.\n */\nexport type SocialServiceCreateSwapCommentAction = {\n type: `SocialService:createSwapComment`;\n handler: SocialService['createSwapComment'];\n};\n\n/**\n * Records that the current user is copying a trade from a social post, so\n * the copy can be detected and attributed to the post's author.\n *\n * Calls `POST ${baseUrl}/copy-trade-intents`. Send swaps before submission\n * with the Bridge quote id, and perps right after submission with the\n * returned order id. The endpoint is idempotent per profile, origin, and\n * execution id: it answers 201 for a new intent and 200 with the existing\n * one on a retry.\n *\n * @param options - Options bag.\n * @param options.origin - Comment the trade was copied from.\n * @param options.copierAccount - CAIP-10 account placing the trade.\n * @param options.execution - Swap quote id or perps order id.\n * @returns The created or existing copy-trade intent.\n */\nexport type SocialServiceCreateCopyTradeIntentAction = {\n type: `SocialService:createCopyTradeIntent`;\n handler: SocialService['createCopyTradeIntent'];\n};\n\n/**\n * Fetches the list of traders the current user is following.\n *\n * Calls `GET ${baseUrl}/users/me/following`. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * Prefer {@link fetchMyFollowing} in new code (pairs with\n * {@link fetchMyFollowers}). This method is unchanged and remains the\n * `/users/me/following` read.\n *\n * @returns The following response.\n */\nexport type SocialServiceFetchFollowingAction = {\n type: `SocialService:fetchFollowing`;\n handler: SocialService['fetchFollowing'];\n};\n\n/**\n * Fetches the list of traders the current user is following.\n *\n * Alias of {@link fetchFollowing}. Calls `GET ${baseUrl}/users/me/following`.\n * Preferred name in new code so `/users/me` reads are both `fetchMy*`.\n *\n * @returns The following response.\n */\nexport type SocialServiceFetchMyFollowingAction = {\n type: `SocialService:fetchMyFollowing`;\n handler: SocialService['fetchMyFollowing'];\n};\n\n/**\n * Fetches the list of traders following the current user.\n *\n * Calls `GET ${baseUrl}/users/me/followers`. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @returns The followers response.\n */\nexport type SocialServiceFetchMyFollowersAction = {\n type: `SocialService:fetchMyFollowers`;\n handler: SocialService['fetchMyFollowers'];\n};\n\n/**\n * Follows one or more traders on behalf of the current user.\n *\n * Calls `PUT ${baseUrl}/users/me/follows`. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.targets - Array of wallet addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\nexport type SocialServiceFollowAction = {\n type: `SocialService:follow`;\n handler: SocialService['follow'];\n};\n\n/**\n * Unfollows one or more traders on behalf of the current user.\n *\n * Calls `DELETE ${baseUrl}/users/me/follows?targets=...`. Targets are sent\n * as query params because Fastify does not parse request bodies on DELETE\n * requests per RFC 9110. The caller is identified server-side from the JWT\n * sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.targets - Array of wallet addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\nexport type SocialServiceUnfollowAction = {\n type: `SocialService:unfollow`;\n handler: SocialService['unfollow'];\n};\n\n/**\n * Opts the current user out of the PnL leaderboard.\n */\nexport type SocialServiceOptOutOfLeaderboardAction = {\n type: `SocialService:optOutOfLeaderboard`;\n handler: SocialService['optOutOfLeaderboard'];\n};\n\n/**\n * Opts the current user back into the PnL leaderboard.\n */\nexport type SocialServiceOptInToLeaderboardAction = {\n type: `SocialService:optInToLeaderboard`;\n handler: SocialService['optInToLeaderboard'];\n};\n\n/**\n * Asks the social-api to refresh its cached copy of the current user's\n * notification preferences.\n *\n * Calls `POST ${baseUrl}/notifications/preferences/cache-refresh`. The caller\n * is identified server-side from the JWT sub claim carried in the\n * Authorization header, so it can only ever refresh its own entry.\n *\n * The client calls this immediately after writing a preference change to\n * Authenticated User Storage (AUS), which is the source of truth. The social\n * api re-reads from AUS and repopulates its cache so the change is honoured\n * near-instantly rather than after the cache TTL lapses. It is a pure\n * optimisation on top of that bounded TTL: the write has already succeeded by\n * the time this runs, so callers should treat it as best-effort and must not\n * roll back the AUS write if it fails.\n */\nexport type SocialServiceRefreshNotificationPreferencesCacheAction = {\n type: `SocialService:refreshNotificationPreferencesCache`;\n handler: SocialService['refreshNotificationPreferencesCache'];\n};\n\n/**\n * Blocks a trader, swap comment, or reply for the current user.\n *\n * Calls `PUT ${baseUrl}/moderation/block`. Provide exactly one of\n * `profileId`, `commentId`, or `replyId`. Blocking the same target again\n * replaces `reason` when one is given. The caller is identified server-side\n * from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag. Exactly one target, plus an optional reason.\n * @param options.profileId - Profile id (UUID) of the trader to block.\n * @param options.commentId - Swap comment to block.\n * @param options.replyId - Comment reply to block.\n * @param options.reason - Free-form reason stored on the block.\n */\nexport type SocialServiceBlockAction = {\n type: `SocialService:block`;\n handler: SocialService['block'];\n};\n\n/**\n * Fetches traders the current user has blocked.\n *\n * Calls `GET ${baseUrl}/moderation/blocks/profiles`. Results are most\n * recently blocked first, 250 per page. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.cursor - Cursor from the previous page. Omit for the first page.\n * @returns The blocked profiles page.\n */\nexport type SocialServiceFetchBlockedProfilesAction = {\n type: `SocialService:fetchBlockedProfiles`;\n handler: SocialService['fetchBlockedProfiles'];\n};\n\n/**\n * Fetches comments and replies the current user has blocked.\n *\n * Calls `GET ${baseUrl}/moderation/blocks/content`. Results are most\n * recently blocked first, 250 per page. The caller is identified\n * server-side from the JWT sub claim carried in the Authorization header.\n *\n * @param options - Options bag.\n * @param options.cursor - Cursor from the previous page. Omit for the first page.\n * @returns The blocked content page.\n */\nexport type SocialServiceFetchBlockedContentAction = {\n type: `SocialService:fetchBlockedContent`;\n handler: SocialService['fetchBlockedContent'];\n};\n\n/**\n * Union of all SocialService action types.\n */\nexport type SocialServiceMethodActions =\n | SocialServiceFetchLeaderboardAction\n | SocialServiceFetchTraderProfileAction\n | SocialServiceFetchOpenPositionsAction\n | SocialServiceFetchClosedPositionsAction\n | SocialServiceFetchFollowersAction\n | SocialServiceFetchTraderFollowingAction\n | SocialServiceFetchPositionByIdAction\n | SocialServiceFetchFeedAction\n | SocialServiceFetchTraderFeedAction\n | SocialServiceFetchTokenFeedAction\n | SocialServiceReactToCommentAction\n | SocialServiceRemoveCommentReactionAction\n | SocialServiceCreateSwapCommentAction\n | SocialServiceCreateCopyTradeIntentAction\n | SocialServiceFetchFollowingAction\n | SocialServiceFetchMyFollowingAction\n | SocialServiceFetchMyFollowersAction\n | SocialServiceFollowAction\n | SocialServiceUnfollowAction\n | SocialServiceOptOutOfLeaderboardAction\n | SocialServiceOptInToLeaderboardAction\n | SocialServiceRefreshNotificationPreferencesCacheAction\n | SocialServiceBlockAction\n | SocialServiceFetchBlockedProfilesAction\n | SocialServiceFetchBlockedContentAction;\n"]}