@metamask/social-controllers 0.1.0 → 1.0.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
+ ## [1.0.0]
11
+
12
+ ### Uncategorized
13
+
14
+ - chore: Format changelogs with Oxfmt ([#8442](https://github.com/MetaMask/core/pull/8442))
15
+
16
+ ### Changed
17
+
18
+ - **BREAKING:** `SocialServiceMessenger` now requires `AuthenticationController:getBearerToken` as an allowed action — all consumers must provide this action via messenger delegation
19
+ - All `SocialService` API requests now include a JWT bearer token in the `Authorization` header, obtained via `AuthenticationController:getBearerToken` ([#8485](https://github.com/MetaMask/core/pull/8485))
20
+
21
+ ## [0.2.0]
22
+
23
+ ### Added
24
+
25
+ - Add optional `tokenImageUrl` field to `Position` type and `PositionStruct` validation schema ([#8448](https://github.com/MetaMask/core/pull/8448))
26
+ - Add optional `medianHoldMinutes` field to `TraderStats` type and `TraderStatsStruct` validation schema ([#8448](https://github.com/MetaMask/core/pull/8448))
27
+ - Add `intent` and optional `category` fields to `Trade` type ([#8410](https://github.com/MetaMask/core/pull/8410))
28
+ - Export `TradeStruct` superstruct schema; derive `Trade` type via `Infer` ([#8410](https://github.com/MetaMask/core/pull/8410))
29
+ - Narrow `direction` to `'buy' | 'sell'` and `intent` to `'enter' | 'exit'` on `Trade` type ([#8410](https://github.com/MetaMask/core/pull/8410))
30
+ - Add `followingProfileIds` to `SocialControllerState` — stores Clicker profile IDs alongside existing `followingAddresses` ([#8459](https://github.com/MetaMask/core/pull/8459))
31
+
32
+ ### Changed
33
+
34
+ - Bump `@metamask/messenger` from `^1.1.0` to `^1.1.1` ([#8373](https://github.com/MetaMask/core/pull/8373))
35
+ - Bump `@metamask/base-controller` from `^9.0.1` to `^9.1.0` ([#8457](https://github.com/MetaMask/core/pull/8457))
36
+
37
+ ### Fixed
38
+
39
+ - Fix `fetchClosedPositions` using v2 URL instead of v1, which caused 404 errors since the closed positions endpoint only exists on v1 ([#8448](https://github.com/MetaMask/core/pull/8448))
40
+
10
41
  ## [0.1.0]
11
42
 
12
43
  ### Added
@@ -20,5 +51,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
20
51
  - `unfollowTrader` — unfollows traders and removes addresses from state
21
52
  - `updateFollowing` — fetches following list and replaces addresses in state
22
53
 
23
- [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@0.1.0...HEAD
54
+ [Unreleased]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@1.0.0...HEAD
55
+ [1.0.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@0.2.0...@metamask/social-controllers@1.0.0
56
+ [0.2.0]: https://github.com/MetaMask/core/compare/@metamask/social-controllers@0.1.0...@metamask/social-controllers@0.2.0
24
57
  [0.1.0]: https://github.com/MetaMask/core/releases/tag/@metamask/social-controllers@0.1.0
@@ -20,6 +20,7 @@ function getDefaultSocialControllerState() {
20
20
  return {
21
21
  leaderboardEntries: [],
22
22
  followingAddresses: [],
23
+ followingProfileIds: [],
23
24
  };
24
25
  }
25
26
  exports.getDefaultSocialControllerState = getDefaultSocialControllerState;
@@ -37,6 +38,12 @@ const socialControllerMetadata = {
37
38
  includeInStateLogs: false,
38
39
  usedInUi: true,
39
40
  },
41
+ followingProfileIds: {
42
+ persist: true,
43
+ includeInDebugSnapshot: false,
44
+ includeInStateLogs: false,
45
+ usedInUi: true,
46
+ },
40
47
  };
41
48
  // === CONTROLLER ===
42
49
  /**
@@ -86,10 +93,16 @@ class SocialController extends base_controller_1.BaseController {
86
93
  const newAddresses = [
87
94
  ...new Set(followResponse.followed.map((profile) => profile.address)),
88
95
  ];
96
+ const newProfileIds = [
97
+ ...new Set(followResponse.followed.map((profile) => profile.profileId)),
98
+ ];
89
99
  this.update((state) => {
90
100
  const existing = new Set(state.followingAddresses);
91
101
  const uniqueNewAddresses = newAddresses.filter((address) => !existing.has(address));
92
102
  state.followingAddresses.push(...uniqueNewAddresses);
103
+ const existingIds = new Set(state.followingProfileIds);
104
+ const uniqueNewIds = newProfileIds.filter((id) => !existingIds.has(id));
105
+ state.followingProfileIds.push(...uniqueNewIds);
93
106
  });
94
107
  return followResponse;
95
108
  }
@@ -104,8 +117,10 @@ class SocialController extends base_controller_1.BaseController {
104
117
  async unfollowTrader(options) {
105
118
  const unfollowResponse = await this.messenger.call('SocialService:unfollow', options);
106
119
  const removedAddresses = new Set(unfollowResponse.unfollowed.map((profile) => profile.address));
120
+ const removedProfileIds = new Set(unfollowResponse.unfollowed.map((profile) => profile.profileId));
107
121
  this.update((state) => {
108
122
  state.followingAddresses = state.followingAddresses.filter((address) => !removedAddresses.has(address));
123
+ state.followingProfileIds = state.followingProfileIds.filter((id) => !removedProfileIds.has(id));
109
124
  });
110
125
  return unfollowResponse;
111
126
  }
@@ -121,6 +136,7 @@ class SocialController extends base_controller_1.BaseController {
121
136
  const followingResponse = await this.messenger.call('SocialService:fetchFollowing', options);
122
137
  this.update((state) => {
123
138
  state.followingAddresses = followingResponse.following.map((profile) => profile.address);
139
+ state.followingProfileIds = followingResponse.following.map((profile) => profile.profileId);
124
140
  });
125
141
  return followingResponse;
126
142
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SocialController.cjs","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport { controllerName } from './social-constants';\nimport type {\n FetchFollowingOptions,\n FetchLeaderboardOptions,\n FollowOptions,\n FollowResponse,\n FollowingResponse,\n LeaderboardResponse,\n SocialControllerState,\n UnfollowOptions,\n UnfollowResponse,\n} from './social-types';\nimport type { SocialControllerMethodActions } from './SocialController-method-action-types';\nimport type {\n SocialServiceFetchFollowingAction,\n SocialServiceFetchLeaderboardAction,\n SocialServiceFollowAction,\n SocialServiceUnfollowAction,\n} from './SocialService-method-action-types';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'updateLeaderboard',\n 'followTrader',\n 'unfollowTrader',\n 'updateFollowing',\n] as const;\n\n// === ACTION TYPES ===\n\nexport type SocialControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerActions =\n | SocialControllerGetStateAction\n | SocialControllerMethodActions;\n\n// === EVENT TYPES ===\n\nexport type SocialControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerEvents = SocialControllerStateChangeEvent;\n\n// === ALLOWED ACTIONS/EVENTS ===\n\ntype AllowedActions =\n | SocialServiceFetchLeaderboardAction\n | SocialServiceFollowAction\n | SocialServiceUnfollowAction\n | SocialServiceFetchFollowingAction;\n\ntype AllowedEvents = never;\n\n// === MESSENGER TYPE ===\n\nexport type SocialControllerMessenger = Messenger<\n typeof controllerName,\n SocialControllerActions | AllowedActions,\n SocialControllerEvents | AllowedEvents\n>;\n\n// === OPTIONS ===\n\nexport type SocialControllerOptions = {\n messenger: SocialControllerMessenger;\n state?: Partial<SocialControllerState>;\n};\n\n// === DEFAULT STATE ===\n\n/**\n * Returns the default state for the SocialController.\n *\n * @returns A fresh default state object.\n */\nexport function getDefaultSocialControllerState(): SocialControllerState {\n return {\n leaderboardEntries: [],\n followingAddresses: [],\n };\n}\n\n// === STATE METADATA ===\n\nconst socialControllerMetadata: StateMetadata<SocialControllerState> = {\n leaderboardEntries: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n followingAddresses: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n};\n\n// === CONTROLLER ===\n\n/**\n * Controller that manages social trading state for the extension UI.\n *\n * Acts as a simple store with no TTL or eviction — the UI decides when\n * to re-fetch, and the social-api's own cache layer handles upstream\n * rate-limiting. State is persisted across sessions so the UI can render\n * immediately on startup while a fresh fetch is in flight.\n */\nexport class SocialController extends BaseController<\n typeof controllerName,\n SocialControllerState,\n SocialControllerMessenger\n> {\n constructor({ messenger, state }: SocialControllerOptions) {\n super({\n name: controllerName,\n metadata: socialControllerMetadata,\n state: {\n ...getDefaultSocialControllerState(),\n ...state,\n },\n messenger,\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Fetches the leaderboard and persists the entries to state.\n *\n * @param options - Optional leaderboard query parameters.\n * @returns The leaderboard response from the social-api.\n */\n async updateLeaderboard(\n options?: FetchLeaderboardOptions,\n ): Promise<LeaderboardResponse> {\n const leaderboardResponse = await this.messenger.call(\n 'SocialService:fetchLeaderboard',\n options,\n );\n\n this.update((state) => {\n state.leaderboardEntries = leaderboardResponse.traders;\n });\n\n return leaderboardResponse;\n }\n\n /**\n * Follows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\n async followTrader(options: FollowOptions): Promise<FollowResponse> {\n const followResponse = await this.messenger.call(\n 'SocialService:follow',\n options,\n );\n\n const newAddresses = [\n ...new Set(followResponse.followed.map((profile) => profile.address)),\n ];\n\n this.update((state) => {\n const existing = new Set(state.followingAddresses);\n const uniqueNewAddresses = newAddresses.filter(\n (address) => !existing.has(address),\n );\n state.followingAddresses.push(...uniqueNewAddresses);\n });\n\n return followResponse;\n }\n\n /**\n * Unfollows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\n async unfollowTrader(options: UnfollowOptions): Promise<UnfollowResponse> {\n const unfollowResponse = await this.messenger.call(\n 'SocialService:unfollow',\n options,\n );\n\n const removedAddresses = new Set(\n unfollowResponse.unfollowed.map((profile) => profile.address),\n );\n\n this.update((state) => {\n state.followingAddresses = state.followingAddresses.filter(\n (address) => !removedAddresses.has(address),\n );\n });\n\n return unfollowResponse;\n }\n\n /**\n * Fetches the list of traders the current user follows and replaces\n * the following addresses in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @returns The following response.\n */\n async updateFollowing(\n options: FetchFollowingOptions,\n ): Promise<FollowingResponse> {\n const followingResponse = await this.messenger.call(\n 'SocialService:fetchFollowing',\n options,\n );\n\n this.update((state) => {\n state.followingAddresses = followingResponse.following.map(\n (profile) => profile.address,\n );\n });\n\n return followingResponse;\n }\n}\n"]}
1
+ {"version":3,"file":"SocialController.cjs","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport { controllerName } from './social-constants';\nimport type {\n FetchFollowingOptions,\n FetchLeaderboardOptions,\n FollowOptions,\n FollowResponse,\n FollowingResponse,\n LeaderboardResponse,\n SocialControllerState,\n UnfollowOptions,\n UnfollowResponse,\n} from './social-types';\nimport type { SocialControllerMethodActions } from './SocialController-method-action-types';\nimport type {\n SocialServiceFetchFollowingAction,\n SocialServiceFetchLeaderboardAction,\n SocialServiceFollowAction,\n SocialServiceUnfollowAction,\n} from './SocialService-method-action-types';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'updateLeaderboard',\n 'followTrader',\n 'unfollowTrader',\n 'updateFollowing',\n] as const;\n\n// === ACTION TYPES ===\n\nexport type SocialControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerActions =\n | SocialControllerGetStateAction\n | SocialControllerMethodActions;\n\n// === EVENT TYPES ===\n\nexport type SocialControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerEvents = SocialControllerStateChangeEvent;\n\n// === ALLOWED ACTIONS/EVENTS ===\n\ntype AllowedActions =\n | SocialServiceFetchLeaderboardAction\n | SocialServiceFollowAction\n | SocialServiceUnfollowAction\n | SocialServiceFetchFollowingAction;\n\ntype AllowedEvents = never;\n\n// === MESSENGER TYPE ===\n\nexport type SocialControllerMessenger = Messenger<\n typeof controllerName,\n SocialControllerActions | AllowedActions,\n SocialControllerEvents | AllowedEvents\n>;\n\n// === OPTIONS ===\n\nexport type SocialControllerOptions = {\n messenger: SocialControllerMessenger;\n state?: Partial<SocialControllerState>;\n};\n\n// === DEFAULT STATE ===\n\n/**\n * Returns the default state for the SocialController.\n *\n * @returns A fresh default state object.\n */\nexport function getDefaultSocialControllerState(): SocialControllerState {\n return {\n leaderboardEntries: [],\n followingAddresses: [],\n followingProfileIds: [],\n };\n}\n\n// === STATE METADATA ===\n\nconst socialControllerMetadata: StateMetadata<SocialControllerState> = {\n leaderboardEntries: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n followingAddresses: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n followingProfileIds: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n};\n\n// === CONTROLLER ===\n\n/**\n * Controller that manages social trading state for the extension UI.\n *\n * Acts as a simple store with no TTL or eviction — the UI decides when\n * to re-fetch, and the social-api's own cache layer handles upstream\n * rate-limiting. State is persisted across sessions so the UI can render\n * immediately on startup while a fresh fetch is in flight.\n */\nexport class SocialController extends BaseController<\n typeof controllerName,\n SocialControllerState,\n SocialControllerMessenger\n> {\n constructor({ messenger, state }: SocialControllerOptions) {\n super({\n name: controllerName,\n metadata: socialControllerMetadata,\n state: {\n ...getDefaultSocialControllerState(),\n ...state,\n },\n messenger,\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Fetches the leaderboard and persists the entries to state.\n *\n * @param options - Optional leaderboard query parameters.\n * @returns The leaderboard response from the social-api.\n */\n async updateLeaderboard(\n options?: FetchLeaderboardOptions,\n ): Promise<LeaderboardResponse> {\n const leaderboardResponse = await this.messenger.call(\n 'SocialService:fetchLeaderboard',\n options,\n );\n\n this.update((state) => {\n state.leaderboardEntries = leaderboardResponse.traders;\n });\n\n return leaderboardResponse;\n }\n\n /**\n * Follows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\n async followTrader(options: FollowOptions): Promise<FollowResponse> {\n const followResponse = await this.messenger.call(\n 'SocialService:follow',\n options,\n );\n\n const newAddresses = [\n ...new Set(followResponse.followed.map((profile) => profile.address)),\n ];\n const newProfileIds = [\n ...new Set(followResponse.followed.map((profile) => profile.profileId)),\n ];\n\n this.update((state) => {\n const existing = new Set(state.followingAddresses);\n const uniqueNewAddresses = newAddresses.filter(\n (address) => !existing.has(address),\n );\n state.followingAddresses.push(...uniqueNewAddresses);\n\n const existingIds = new Set(state.followingProfileIds);\n const uniqueNewIds = newProfileIds.filter((id) => !existingIds.has(id));\n state.followingProfileIds.push(...uniqueNewIds);\n });\n\n return followResponse;\n }\n\n /**\n * Unfollows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\n async unfollowTrader(options: UnfollowOptions): Promise<UnfollowResponse> {\n const unfollowResponse = await this.messenger.call(\n 'SocialService:unfollow',\n options,\n );\n\n const removedAddresses = new Set(\n unfollowResponse.unfollowed.map((profile) => profile.address),\n );\n const removedProfileIds = new Set(\n unfollowResponse.unfollowed.map((profile) => profile.profileId),\n );\n\n this.update((state) => {\n state.followingAddresses = state.followingAddresses.filter(\n (address) => !removedAddresses.has(address),\n );\n state.followingProfileIds = state.followingProfileIds.filter(\n (id) => !removedProfileIds.has(id),\n );\n });\n\n return unfollowResponse;\n }\n\n /**\n * Fetches the list of traders the current user follows and replaces\n * the following addresses in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @returns The following response.\n */\n async updateFollowing(\n options: FetchFollowingOptions,\n ): Promise<FollowingResponse> {\n const followingResponse = await this.messenger.call(\n 'SocialService:fetchFollowing',\n options,\n );\n\n this.update((state) => {\n state.followingAddresses = followingResponse.following.map(\n (profile) => profile.address,\n );\n state.followingProfileIds = followingResponse.following.map(\n (profile) => profile.profileId,\n );\n });\n\n return followingResponse;\n }\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"SocialController.d.cts","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EACjB,2BAAuB;AACxB,OAAO,KAAK,EAAE,6BAA6B,EAAE,mDAA+C;AAC5F,OAAO,KAAK,EACV,iCAAiC,EACjC,mCAAmC,EACnC,yBAAyB,EACzB,2BAA2B,EAC5B,gDAA4C;AAa7C,MAAM,MAAM,8BAA8B,GAAG,wBAAwB,CACnE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,8BAA8B,GAC9B,6BAA6B,CAAC;AAIlC,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,gCAAgC,CAAC;AAItE,KAAK,cAAc,GACf,mCAAmC,GACnC,yBAAyB,GACzB,2BAA2B,GAC3B,iCAAiC,CAAC;AAEtC,KAAK,aAAa,GAAG,KAAK,CAAC;AAI3B,MAAM,MAAM,yBAAyB,GAAG,SAAS,CAC/C,OAAO,cAAc,EACrB,uBAAuB,GAAG,cAAc,EACxC,sBAAsB,GAAG,aAAa,CACvC,CAAC;AAIF,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,qBAAqB,CAKvE;AAqBD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,cAAc,CAClD,OAAO,cAAc,EACrB,qBAAqB,EACrB,yBAAyB,CAC1B;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,uBAAuB;IAiBzD;;;;;OAKG;IACG,iBAAiB,CACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAa/B;;;;;;;OAOG;IACG,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAqBnE;;;;;;;OAOG;IACG,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmBzE;;;;;;;OAOG;IACG,eAAe,CACnB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;CAc9B"}
1
+ {"version":3,"file":"SocialController.d.cts","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EACjB,2BAAuB;AACxB,OAAO,KAAK,EAAE,6BAA6B,EAAE,mDAA+C;AAC5F,OAAO,KAAK,EACV,iCAAiC,EACjC,mCAAmC,EACnC,yBAAyB,EACzB,2BAA2B,EAC5B,gDAA4C;AAa7C,MAAM,MAAM,8BAA8B,GAAG,wBAAwB,CACnE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,8BAA8B,GAC9B,6BAA6B,CAAC;AAIlC,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,gCAAgC,CAAC;AAItE,KAAK,cAAc,GACf,mCAAmC,GACnC,yBAAyB,GACzB,2BAA2B,GAC3B,iCAAiC,CAAC;AAEtC,KAAK,aAAa,GAAG,KAAK,CAAC;AAI3B,MAAM,MAAM,yBAAyB,GAAG,SAAS,CAC/C,OAAO,cAAc,EACrB,uBAAuB,GAAG,cAAc,EACxC,sBAAsB,GAAG,aAAa,CACvC,CAAC;AAIF,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,qBAAqB,CAMvE;AA2BD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,cAAc,CAClD,OAAO,cAAc,EACrB,qBAAqB,EACrB,yBAAyB,CAC1B;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,uBAAuB;IAiBzD;;;;;OAKG;IACG,iBAAiB,CACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAa/B;;;;;;;OAOG;IACG,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IA4BnE;;;;;;;OAOG;IACG,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyBzE;;;;;;;OAOG;IACG,eAAe,CACnB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;CAiB9B"}
@@ -1 +1 @@
1
- {"version":3,"file":"SocialController.d.mts","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EACjB,2BAAuB;AACxB,OAAO,KAAK,EAAE,6BAA6B,EAAE,mDAA+C;AAC5F,OAAO,KAAK,EACV,iCAAiC,EACjC,mCAAmC,EACnC,yBAAyB,EACzB,2BAA2B,EAC5B,gDAA4C;AAa7C,MAAM,MAAM,8BAA8B,GAAG,wBAAwB,CACnE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,8BAA8B,GAC9B,6BAA6B,CAAC;AAIlC,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,gCAAgC,CAAC;AAItE,KAAK,cAAc,GACf,mCAAmC,GACnC,yBAAyB,GACzB,2BAA2B,GAC3B,iCAAiC,CAAC;AAEtC,KAAK,aAAa,GAAG,KAAK,CAAC;AAI3B,MAAM,MAAM,yBAAyB,GAAG,SAAS,CAC/C,OAAO,cAAc,EACrB,uBAAuB,GAAG,cAAc,EACxC,sBAAsB,GAAG,aAAa,CACvC,CAAC;AAIF,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,qBAAqB,CAKvE;AAqBD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,cAAc,CAClD,OAAO,cAAc,EACrB,qBAAqB,EACrB,yBAAyB,CAC1B;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,uBAAuB;IAiBzD;;;;;OAKG;IACG,iBAAiB,CACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAa/B;;;;;;;OAOG;IACG,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IAqBnE;;;;;;;OAOG;IACG,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAmBzE;;;;;;;OAOG;IACG,eAAe,CACnB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;CAc9B"}
1
+ {"version":3,"file":"SocialController.d.mts","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,wBAAwB,EACxB,0BAA0B,EAE3B,kCAAkC;AACnC,OAAO,EAAE,cAAc,EAAE,kCAAkC;AAC3D,OAAO,KAAK,EAAE,SAAS,EAAE,4BAA4B;AAErD,OAAO,EAAE,cAAc,EAAE,+BAA2B;AACpD,OAAO,KAAK,EACV,qBAAqB,EACrB,uBAAuB,EACvB,aAAa,EACb,cAAc,EACd,iBAAiB,EACjB,mBAAmB,EACnB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EACjB,2BAAuB;AACxB,OAAO,KAAK,EAAE,6BAA6B,EAAE,mDAA+C;AAC5F,OAAO,KAAK,EACV,iCAAiC,EACjC,mCAAmC,EACnC,yBAAyB,EACzB,2BAA2B,EAC5B,gDAA4C;AAa7C,MAAM,MAAM,8BAA8B,GAAG,wBAAwB,CACnE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,uBAAuB,GAC/B,8BAA8B,GAC9B,6BAA6B,CAAC;AAIlC,MAAM,MAAM,gCAAgC,GAAG,0BAA0B,CACvE,OAAO,cAAc,EACrB,qBAAqB,CACtB,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG,gCAAgC,CAAC;AAItE,KAAK,cAAc,GACf,mCAAmC,GACnC,yBAAyB,GACzB,2BAA2B,GAC3B,iCAAiC,CAAC;AAEtC,KAAK,aAAa,GAAG,KAAK,CAAC;AAI3B,MAAM,MAAM,yBAAyB,GAAG,SAAS,CAC/C,OAAO,cAAc,EACrB,uBAAuB,GAAG,cAAc,EACxC,sBAAsB,GAAG,aAAa,CACvC,CAAC;AAIF,MAAM,MAAM,uBAAuB,GAAG;IACpC,SAAS,EAAE,yBAAyB,CAAC;IACrC,KAAK,CAAC,EAAE,OAAO,CAAC,qBAAqB,CAAC,CAAC;CACxC,CAAC;AAIF;;;;GAIG;AACH,wBAAgB,+BAA+B,IAAI,qBAAqB,CAMvE;AA2BD;;;;;;;GAOG;AACH,qBAAa,gBAAiB,SAAQ,cAAc,CAClD,OAAO,cAAc,EACrB,qBAAqB,EACrB,yBAAyB,CAC1B;gBACa,EAAE,SAAS,EAAE,KAAK,EAAE,EAAE,uBAAuB;IAiBzD;;;;;OAKG;IACG,iBAAiB,CACrB,OAAO,CAAC,EAAE,uBAAuB,GAChC,OAAO,CAAC,mBAAmB,CAAC;IAa/B;;;;;;;OAOG;IACG,YAAY,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,cAAc,CAAC;IA4BnE;;;;;;;OAOG;IACG,cAAc,CAAC,OAAO,EAAE,eAAe,GAAG,OAAO,CAAC,gBAAgB,CAAC;IAyBzE;;;;;;;OAOG;IACG,eAAe,CACnB,OAAO,EAAE,qBAAqB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;CAiB9B"}
@@ -17,6 +17,7 @@ export function getDefaultSocialControllerState() {
17
17
  return {
18
18
  leaderboardEntries: [],
19
19
  followingAddresses: [],
20
+ followingProfileIds: [],
20
21
  };
21
22
  }
22
23
  // === STATE METADATA ===
@@ -33,6 +34,12 @@ const socialControllerMetadata = {
33
34
  includeInStateLogs: false,
34
35
  usedInUi: true,
35
36
  },
37
+ followingProfileIds: {
38
+ persist: true,
39
+ includeInDebugSnapshot: false,
40
+ includeInStateLogs: false,
41
+ usedInUi: true,
42
+ },
36
43
  };
37
44
  // === CONTROLLER ===
38
45
  /**
@@ -82,10 +89,16 @@ export class SocialController extends BaseController {
82
89
  const newAddresses = [
83
90
  ...new Set(followResponse.followed.map((profile) => profile.address)),
84
91
  ];
92
+ const newProfileIds = [
93
+ ...new Set(followResponse.followed.map((profile) => profile.profileId)),
94
+ ];
85
95
  this.update((state) => {
86
96
  const existing = new Set(state.followingAddresses);
87
97
  const uniqueNewAddresses = newAddresses.filter((address) => !existing.has(address));
88
98
  state.followingAddresses.push(...uniqueNewAddresses);
99
+ const existingIds = new Set(state.followingProfileIds);
100
+ const uniqueNewIds = newProfileIds.filter((id) => !existingIds.has(id));
101
+ state.followingProfileIds.push(...uniqueNewIds);
89
102
  });
90
103
  return followResponse;
91
104
  }
@@ -100,8 +113,10 @@ export class SocialController extends BaseController {
100
113
  async unfollowTrader(options) {
101
114
  const unfollowResponse = await this.messenger.call('SocialService:unfollow', options);
102
115
  const removedAddresses = new Set(unfollowResponse.unfollowed.map((profile) => profile.address));
116
+ const removedProfileIds = new Set(unfollowResponse.unfollowed.map((profile) => profile.profileId));
103
117
  this.update((state) => {
104
118
  state.followingAddresses = state.followingAddresses.filter((address) => !removedAddresses.has(address));
119
+ state.followingProfileIds = state.followingProfileIds.filter((id) => !removedProfileIds.has(id));
105
120
  });
106
121
  return unfollowResponse;
107
122
  }
@@ -117,6 +132,7 @@ export class SocialController extends BaseController {
117
132
  const followingResponse = await this.messenger.call('SocialService:fetchFollowing', options);
118
133
  this.update((state) => {
119
134
  state.followingAddresses = followingResponse.following.map((profile) => profile.address);
135
+ state.followingProfileIds = followingResponse.following.map((profile) => profile.profileId);
120
136
  });
121
137
  return followingResponse;
122
138
  }
@@ -1 +1 @@
1
- {"version":3,"file":"SocialController.mjs","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport { controllerName } from './social-constants';\nimport type {\n FetchFollowingOptions,\n FetchLeaderboardOptions,\n FollowOptions,\n FollowResponse,\n FollowingResponse,\n LeaderboardResponse,\n SocialControllerState,\n UnfollowOptions,\n UnfollowResponse,\n} from './social-types';\nimport type { SocialControllerMethodActions } from './SocialController-method-action-types';\nimport type {\n SocialServiceFetchFollowingAction,\n SocialServiceFetchLeaderboardAction,\n SocialServiceFollowAction,\n SocialServiceUnfollowAction,\n} from './SocialService-method-action-types';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'updateLeaderboard',\n 'followTrader',\n 'unfollowTrader',\n 'updateFollowing',\n] as const;\n\n// === ACTION TYPES ===\n\nexport type SocialControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerActions =\n | SocialControllerGetStateAction\n | SocialControllerMethodActions;\n\n// === EVENT TYPES ===\n\nexport type SocialControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerEvents = SocialControllerStateChangeEvent;\n\n// === ALLOWED ACTIONS/EVENTS ===\n\ntype AllowedActions =\n | SocialServiceFetchLeaderboardAction\n | SocialServiceFollowAction\n | SocialServiceUnfollowAction\n | SocialServiceFetchFollowingAction;\n\ntype AllowedEvents = never;\n\n// === MESSENGER TYPE ===\n\nexport type SocialControllerMessenger = Messenger<\n typeof controllerName,\n SocialControllerActions | AllowedActions,\n SocialControllerEvents | AllowedEvents\n>;\n\n// === OPTIONS ===\n\nexport type SocialControllerOptions = {\n messenger: SocialControllerMessenger;\n state?: Partial<SocialControllerState>;\n};\n\n// === DEFAULT STATE ===\n\n/**\n * Returns the default state for the SocialController.\n *\n * @returns A fresh default state object.\n */\nexport function getDefaultSocialControllerState(): SocialControllerState {\n return {\n leaderboardEntries: [],\n followingAddresses: [],\n };\n}\n\n// === STATE METADATA ===\n\nconst socialControllerMetadata: StateMetadata<SocialControllerState> = {\n leaderboardEntries: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n followingAddresses: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n};\n\n// === CONTROLLER ===\n\n/**\n * Controller that manages social trading state for the extension UI.\n *\n * Acts as a simple store with no TTL or eviction — the UI decides when\n * to re-fetch, and the social-api's own cache layer handles upstream\n * rate-limiting. State is persisted across sessions so the UI can render\n * immediately on startup while a fresh fetch is in flight.\n */\nexport class SocialController extends BaseController<\n typeof controllerName,\n SocialControllerState,\n SocialControllerMessenger\n> {\n constructor({ messenger, state }: SocialControllerOptions) {\n super({\n name: controllerName,\n metadata: socialControllerMetadata,\n state: {\n ...getDefaultSocialControllerState(),\n ...state,\n },\n messenger,\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Fetches the leaderboard and persists the entries to state.\n *\n * @param options - Optional leaderboard query parameters.\n * @returns The leaderboard response from the social-api.\n */\n async updateLeaderboard(\n options?: FetchLeaderboardOptions,\n ): Promise<LeaderboardResponse> {\n const leaderboardResponse = await this.messenger.call(\n 'SocialService:fetchLeaderboard',\n options,\n );\n\n this.update((state) => {\n state.leaderboardEntries = leaderboardResponse.traders;\n });\n\n return leaderboardResponse;\n }\n\n /**\n * Follows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\n async followTrader(options: FollowOptions): Promise<FollowResponse> {\n const followResponse = await this.messenger.call(\n 'SocialService:follow',\n options,\n );\n\n const newAddresses = [\n ...new Set(followResponse.followed.map((profile) => profile.address)),\n ];\n\n this.update((state) => {\n const existing = new Set(state.followingAddresses);\n const uniqueNewAddresses = newAddresses.filter(\n (address) => !existing.has(address),\n );\n state.followingAddresses.push(...uniqueNewAddresses);\n });\n\n return followResponse;\n }\n\n /**\n * Unfollows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\n async unfollowTrader(options: UnfollowOptions): Promise<UnfollowResponse> {\n const unfollowResponse = await this.messenger.call(\n 'SocialService:unfollow',\n options,\n );\n\n const removedAddresses = new Set(\n unfollowResponse.unfollowed.map((profile) => profile.address),\n );\n\n this.update((state) => {\n state.followingAddresses = state.followingAddresses.filter(\n (address) => !removedAddresses.has(address),\n );\n });\n\n return unfollowResponse;\n }\n\n /**\n * Fetches the list of traders the current user follows and replaces\n * the following addresses in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @returns The following response.\n */\n async updateFollowing(\n options: FetchFollowingOptions,\n ): Promise<FollowingResponse> {\n const followingResponse = await this.messenger.call(\n 'SocialService:fetchFollowing',\n options,\n );\n\n this.update((state) => {\n state.followingAddresses = followingResponse.following.map(\n (profile) => profile.address,\n );\n });\n\n return followingResponse;\n }\n}\n"]}
1
+ {"version":3,"file":"SocialController.mjs","sourceRoot":"","sources":["../src/SocialController.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n ControllerGetStateAction,\n ControllerStateChangeEvent,\n StateMetadata,\n} from '@metamask/base-controller';\nimport { BaseController } from '@metamask/base-controller';\nimport type { Messenger } from '@metamask/messenger';\n\nimport { controllerName } from './social-constants';\nimport type {\n FetchFollowingOptions,\n FetchLeaderboardOptions,\n FollowOptions,\n FollowResponse,\n FollowingResponse,\n LeaderboardResponse,\n SocialControllerState,\n UnfollowOptions,\n UnfollowResponse,\n} from './social-types';\nimport type { SocialControllerMethodActions } from './SocialController-method-action-types';\nimport type {\n SocialServiceFetchFollowingAction,\n SocialServiceFetchLeaderboardAction,\n SocialServiceFollowAction,\n SocialServiceUnfollowAction,\n} from './SocialService-method-action-types';\n\n// === MESSENGER ===\n\nconst MESSENGER_EXPOSED_METHODS = [\n 'updateLeaderboard',\n 'followTrader',\n 'unfollowTrader',\n 'updateFollowing',\n] as const;\n\n// === ACTION TYPES ===\n\nexport type SocialControllerGetStateAction = ControllerGetStateAction<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerActions =\n | SocialControllerGetStateAction\n | SocialControllerMethodActions;\n\n// === EVENT TYPES ===\n\nexport type SocialControllerStateChangeEvent = ControllerStateChangeEvent<\n typeof controllerName,\n SocialControllerState\n>;\n\nexport type SocialControllerEvents = SocialControllerStateChangeEvent;\n\n// === ALLOWED ACTIONS/EVENTS ===\n\ntype AllowedActions =\n | SocialServiceFetchLeaderboardAction\n | SocialServiceFollowAction\n | SocialServiceUnfollowAction\n | SocialServiceFetchFollowingAction;\n\ntype AllowedEvents = never;\n\n// === MESSENGER TYPE ===\n\nexport type SocialControllerMessenger = Messenger<\n typeof controllerName,\n SocialControllerActions | AllowedActions,\n SocialControllerEvents | AllowedEvents\n>;\n\n// === OPTIONS ===\n\nexport type SocialControllerOptions = {\n messenger: SocialControllerMessenger;\n state?: Partial<SocialControllerState>;\n};\n\n// === DEFAULT STATE ===\n\n/**\n * Returns the default state for the SocialController.\n *\n * @returns A fresh default state object.\n */\nexport function getDefaultSocialControllerState(): SocialControllerState {\n return {\n leaderboardEntries: [],\n followingAddresses: [],\n followingProfileIds: [],\n };\n}\n\n// === STATE METADATA ===\n\nconst socialControllerMetadata: StateMetadata<SocialControllerState> = {\n leaderboardEntries: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n followingAddresses: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n followingProfileIds: {\n persist: true,\n includeInDebugSnapshot: false,\n includeInStateLogs: false,\n usedInUi: true,\n },\n};\n\n// === CONTROLLER ===\n\n/**\n * Controller that manages social trading state for the extension UI.\n *\n * Acts as a simple store with no TTL or eviction — the UI decides when\n * to re-fetch, and the social-api's own cache layer handles upstream\n * rate-limiting. State is persisted across sessions so the UI can render\n * immediately on startup while a fresh fetch is in flight.\n */\nexport class SocialController extends BaseController<\n typeof controllerName,\n SocialControllerState,\n SocialControllerMessenger\n> {\n constructor({ messenger, state }: SocialControllerOptions) {\n super({\n name: controllerName,\n metadata: socialControllerMetadata,\n state: {\n ...getDefaultSocialControllerState(),\n ...state,\n },\n messenger,\n });\n\n this.messenger.registerMethodActionHandlers(\n this,\n MESSENGER_EXPOSED_METHODS,\n );\n }\n\n /**\n * Fetches the leaderboard and persists the entries to state.\n *\n * @param options - Optional leaderboard query parameters.\n * @returns The leaderboard response from the social-api.\n */\n async updateLeaderboard(\n options?: FetchLeaderboardOptions,\n ): Promise<LeaderboardResponse> {\n const leaderboardResponse = await this.messenger.call(\n 'SocialService:fetchLeaderboard',\n options,\n );\n\n this.update((state) => {\n state.leaderboardEntries = leaderboardResponse.traders;\n });\n\n return leaderboardResponse;\n }\n\n /**\n * Follows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to follow.\n * @returns The follow response with confirmed follows.\n */\n async followTrader(options: FollowOptions): Promise<FollowResponse> {\n const followResponse = await this.messenger.call(\n 'SocialService:follow',\n options,\n );\n\n const newAddresses = [\n ...new Set(followResponse.followed.map((profile) => profile.address)),\n ];\n const newProfileIds = [\n ...new Set(followResponse.followed.map((profile) => profile.profileId)),\n ];\n\n this.update((state) => {\n const existing = new Set(state.followingAddresses);\n const uniqueNewAddresses = newAddresses.filter(\n (address) => !existing.has(address),\n );\n state.followingAddresses.push(...uniqueNewAddresses);\n\n const existingIds = new Set(state.followingProfileIds);\n const uniqueNewIds = newProfileIds.filter((id) => !existingIds.has(id));\n state.followingProfileIds.push(...uniqueNewIds);\n });\n\n return followResponse;\n }\n\n /**\n * Unfollows one or more traders and updates the following list in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @param options.targets - Addresses or profile IDs to unfollow.\n * @returns The unfollow response with confirmed unfollows.\n */\n async unfollowTrader(options: UnfollowOptions): Promise<UnfollowResponse> {\n const unfollowResponse = await this.messenger.call(\n 'SocialService:unfollow',\n options,\n );\n\n const removedAddresses = new Set(\n unfollowResponse.unfollowed.map((profile) => profile.address),\n );\n const removedProfileIds = new Set(\n unfollowResponse.unfollowed.map((profile) => profile.profileId),\n );\n\n this.update((state) => {\n state.followingAddresses = state.followingAddresses.filter(\n (address) => !removedAddresses.has(address),\n );\n state.followingProfileIds = state.followingProfileIds.filter(\n (id) => !removedProfileIds.has(id),\n );\n });\n\n return unfollowResponse;\n }\n\n /**\n * Fetches the list of traders the current user follows and replaces\n * the following addresses in state.\n *\n * @param options - Options bag.\n * @param options.addressOrUid - Wallet address or Clicker profile ID of the current user.\n * @returns The following response.\n */\n async updateFollowing(\n options: FetchFollowingOptions,\n ): Promise<FollowingResponse> {\n const followingResponse = await this.messenger.call(\n 'SocialService:fetchFollowing',\n options,\n );\n\n this.update((state) => {\n state.followingAddresses = followingResponse.following.map(\n (profile) => profile.address,\n );\n state.followingProfileIds = followingResponse.following.map(\n (profile) => profile.profileId,\n );\n });\n\n return followingResponse;\n }\n}\n"]}
@@ -10,13 +10,14 @@ var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (
10
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
11
  return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
12
12
  };
13
- var _SocialService_instances, _a, _SocialService_baseUrl, _SocialService_v1Url_get, _SocialService_v2Url_get, _SocialService_throwIfNotOk, _SocialService_fetchPositions;
13
+ var _SocialService_instances, _a, _SocialService_baseUrl, _SocialService_v1Url_get, _SocialService_v2Url_get, _SocialService_throwIfNotOk, _SocialService_getAuthHeaders, _SocialService_fetchPositions;
14
14
  Object.defineProperty(exports, "__esModule", { value: true });
15
15
  exports.SocialService = void 0;
16
16
  const base_data_service_1 = require("@metamask/base-data-service");
17
17
  const controller_utils_1 = require("@metamask/controller-utils");
18
18
  const superstruct_1 = require("@metamask/superstruct");
19
19
  const social_constants_1 = require("./social-constants.cjs");
20
+ const social_types_1 = require("./social-types.cjs");
20
21
  // ---------------------------------------------------------------------------
21
22
  // Superstruct validation schemas
22
23
  // ---------------------------------------------------------------------------
@@ -32,13 +33,6 @@ const ProfileSummaryStruct = (0, superstruct_1.type)({
32
33
  name: (0, superstruct_1.string)(),
33
34
  imageUrl: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
34
35
  });
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
36
  const PositionStruct = (0, superstruct_1.type)({
43
37
  tokenSymbol: (0, superstruct_1.string)(),
44
38
  tokenName: (0, superstruct_1.string)(),
@@ -49,8 +43,9 @@ const PositionStruct = (0, superstruct_1.type)({
49
43
  soldUsd: (0, superstruct_1.number)(),
50
44
  realizedPnl: (0, superstruct_1.number)(),
51
45
  costBasis: (0, superstruct_1.number)(),
52
- trades: (0, superstruct_1.array)(TradeStruct),
46
+ trades: (0, superstruct_1.array)(social_types_1.TradeStruct),
53
47
  lastTradeAt: (0, superstruct_1.number)(),
48
+ tokenImageUrl: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.string)())),
54
49
  currentValueUSD: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
55
50
  pnlValueUsd: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
56
51
  pnlPercent: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
@@ -96,6 +91,7 @@ const TraderStatsStruct = (0, superstruct_1.type)({
96
91
  winRate7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
97
92
  roiPercent7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
98
93
  tradeCount7d: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
94
+ medianHoldMinutes: (0, superstruct_1.optional)((0, superstruct_1.nullable)((0, superstruct_1.number)())),
99
95
  });
100
96
  const PerChainBreakdownStruct = (0, superstruct_1.type)({
101
97
  perChainPnl: (0, superstruct_1.record)((0, superstruct_1.string)(), (0, superstruct_1.number)()),
@@ -181,7 +177,10 @@ class SocialService extends base_data_service_1.BaseDataService {
181
177
  if (limit !== undefined) {
182
178
  url.searchParams.append('limit', String(limit));
183
179
  }
184
- const response = await fetch(url.toString());
180
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
181
+ const response = await fetch(url.toString(), {
182
+ headers: authHeaders,
183
+ });
185
184
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_LEADERBOARD_FAILED);
186
185
  const leaderboardData = await response.json();
187
186
  if (!(0, superstruct_1.is)(leaderboardData, LeaderboardResponseStruct)) {
@@ -207,7 +206,8 @@ class SocialService extends base_data_service_1.BaseDataService {
207
206
  queryKey: [`${this.name}:fetchTraderProfile`, addressOrId],
208
207
  queryFn: async () => {
209
208
  const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/traders/${encodeURIComponent(addressOrId)}/profile`;
210
- const response = await fetch(url);
209
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
210
+ const response = await fetch(url, { headers: authHeaders });
211
211
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_TRADER_PROFILE_FAILED);
212
212
  const traderProfileData = await response.json();
213
213
  if (!(0, superstruct_1.is)(traderProfileData, TraderProfileResponseStruct)) {
@@ -265,7 +265,8 @@ class SocialService extends base_data_service_1.BaseDataService {
265
265
  queryKey: [`${this.name}:fetchFollowers`, addressOrId],
266
266
  queryFn: async () => {
267
267
  const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/traders/${encodeURIComponent(addressOrId)}/followers`;
268
- const response = await fetch(url);
268
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
269
+ const response = await fetch(url, { headers: authHeaders });
269
270
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_FOLLOWERS_FAILED);
270
271
  const followersData = await response.json();
271
272
  if (!(0, superstruct_1.is)(followersData, FollowersResponseStruct)) {
@@ -292,7 +293,8 @@ class SocialService extends base_data_service_1.BaseDataService {
292
293
  staleTime: 0,
293
294
  queryFn: async () => {
294
295
  const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/users/${encodeURIComponent(addressOrUid)}/following`;
295
- const response = await fetch(url);
296
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
297
+ const response = await fetch(url, { headers: authHeaders });
296
298
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FETCH_FOLLOWING_FAILED);
297
299
  const followingData = await response.json();
298
300
  if (!(0, superstruct_1.is)(followingData, FollowingResponseStruct)) {
@@ -320,9 +322,10 @@ class SocialService extends base_data_service_1.BaseDataService {
320
322
  staleTime: 0,
321
323
  queryFn: async () => {
322
324
  const url = `${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get)}/users/${encodeURIComponent(addressOrUid)}/follows`;
325
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
323
326
  const response = await fetch(url, {
324
327
  method: 'PUT',
325
- headers: { 'Content-Type': 'application/json' },
328
+ headers: { ...authHeaders, 'Content-Type': 'application/json' },
326
329
  body: JSON.stringify({ targets }),
327
330
  });
328
331
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.FOLLOW_FAILED);
@@ -357,7 +360,11 @@ class SocialService extends base_data_service_1.BaseDataService {
357
360
  for (const target of targets) {
358
361
  url.searchParams.append('targets', target);
359
362
  }
360
- const response = await fetch(url.toString(), { method: 'DELETE' });
363
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
364
+ const response = await fetch(url.toString(), {
365
+ method: 'DELETE',
366
+ headers: authHeaders,
367
+ });
361
368
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, social_constants_1.SocialServiceErrorMessage.UNFOLLOW_FAILED);
362
369
  const unfollowData = await response.json();
363
370
  if (!(0, superstruct_1.is)(unfollowData, UnfollowResponseStruct)) {
@@ -378,6 +385,16 @@ _a = SocialService, _SocialService_baseUrl = new WeakMap(), _SocialService_insta
378
385
  if (!response.ok) {
379
386
  throw new controller_utils_1.HttpError(response.status, `${message}: ${response.status}`);
380
387
  }
388
+ }, _SocialService_getAuthHeaders =
389
+ /**
390
+ * Returns an Authorization header with a JWT bearer token obtained from the
391
+ * AuthenticationController.
392
+ *
393
+ * @returns A headers object containing the Authorization header.
394
+ */
395
+ async function _SocialService_getAuthHeaders() {
396
+ const token = await this.messenger.call('AuthenticationController:getBearerToken');
397
+ return { Authorization: `Bearer ${token}` };
381
398
  }, _SocialService_fetchPositions =
382
399
  /**
383
400
  * Shared helper for fetching open/closed positions.
@@ -406,7 +423,8 @@ async function _SocialService_fetchPositions(status, options) {
406
423
  page ?? null,
407
424
  ],
408
425
  queryFn: async () => {
409
- const url = new URL(`${__classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v2Url_get)}/traders/${encodeURIComponent(addressOrId)}/positions/${status}`);
426
+ const baseUrl = status === 'open' ? __classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v2Url_get) : __classPrivateFieldGet(this, _SocialService_instances, "a", _SocialService_v1Url_get);
427
+ const url = new URL(`${baseUrl}/traders/${encodeURIComponent(addressOrId)}/positions/${status}`);
410
428
  if (chain) {
411
429
  url.searchParams.append('chain', chain);
412
430
  }
@@ -420,7 +438,10 @@ async function _SocialService_fetchPositions(status, options) {
420
438
  if (page !== undefined) {
421
439
  url.searchParams.append('page', String(page));
422
440
  }
423
- const response = await fetch(url.toString());
441
+ const authHeaders = await __classPrivateFieldGet(this, _SocialService_instances, "m", _SocialService_getAuthHeaders).call(this);
442
+ const response = await fetch(url.toString(), {
443
+ headers: authHeaders,
444
+ });
424
445
  __classPrivateFieldGet(_a, _a, "m", _SocialService_throwIfNotOk).call(_a, response, failedMessage);
425
446
  const positionsData = await response.json();
426
447
  if (!(0, superstruct_1.is)(positionsData, PositionsResponseStruct)) {
@@ -1 +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"]}
1
+ {"version":3,"file":"SocialService.cjs","sourceRoot":"","sources":["../src/SocialService.ts"],"names":[],"mappings":"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","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 type { AuthenticationController } from '@metamask/profile-sync-controller';\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 { TradeStruct } 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 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 tokenImageUrl: optional(nullable(string())),\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 medianHoldMinutes: 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\ntype AllowedActions =\n AuthenticationController.AuthenticationControllerGetBearerTokenAction;\n\ntype AllowedEvents = never;\n\nexport type SocialServiceMessenger = Messenger<\n typeof serviceName,\n SocialServiceActions | AllowedActions,\n SocialServiceEvents | AllowedEvents\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 * Returns an Authorization header with a JWT bearer token obtained from the\n * AuthenticationController.\n *\n * @returns A headers object containing the Authorization header.\n */\n async #getAuthHeaders(): Promise<Record<string, string>> {\n const token = await this.messenger.call(\n 'AuthenticationController:getBearerToken',\n );\n return { Authorization: `Bearer ${token}` };\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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url.toString(), {\n headers: authHeaders,\n });\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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url, { headers: authHeaders });\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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url, { headers: authHeaders });\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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url, { headers: authHeaders });\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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url, {\n method: 'PUT',\n headers: { ...authHeaders, '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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url.toString(), {\n method: 'DELETE',\n headers: authHeaders,\n });\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 baseUrl = status === 'open' ? this.#v2Url : this.#v1Url;\n const url = new URL(\n `${baseUrl}/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 authHeaders = await this.#getAuthHeaders();\n const response = await fetch(url.toString(), {\n headers: authHeaders,\n });\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"]}