@nadohq/mobile-client 0.64.0 → 0.66.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (225) hide show
  1. package/README.md +124 -7
  2. package/dist/MobileClient-M4oC4lrX.cjs +1101 -0
  3. package/dist/MobileClient-M4oC4lrX.cjs.map +1 -0
  4. package/dist/MobileClient.cjs +1 -1
  5. package/dist/MobileClient.d.cts +306 -10
  6. package/dist/MobileClient.d.cts.map +1 -1
  7. package/dist/MobileClient.d.ts +306 -10
  8. package/dist/MobileClient.d.ts.map +1 -1
  9. package/dist/MobileClient.js +544 -5
  10. package/dist/MobileClient.js.map +1 -1
  11. package/dist/{MobileServerFailureError-Dd3c6P_Z.d.ts → MobileServerFailureError-C9iqNsxI.d.ts} +2 -3
  12. package/dist/MobileServerFailureError-C9iqNsxI.d.ts.map +1 -0
  13. package/dist/{MobileServerFailureError-Bpa_WA9f.d.cts → MobileServerFailureError-MtS2reel.d.cts} +2 -3
  14. package/dist/MobileServerFailureError-MtS2reel.d.cts.map +1 -0
  15. package/dist/MobileUnsupportedFeedItemError-BsZvW8i2.d.cts +15 -0
  16. package/dist/MobileUnsupportedFeedItemError-BsZvW8i2.d.cts.map +1 -0
  17. package/dist/MobileUnsupportedFeedItemError-BsZvW8i2.d.ts +15 -0
  18. package/dist/MobileUnsupportedFeedItemError-BsZvW8i2.d.ts.map +1 -0
  19. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.cts +15 -0
  20. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.cts.map +1 -0
  21. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.ts +15 -0
  22. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.ts.map +1 -0
  23. package/dist/{buildSignedMobileRequest-Cb1T74xV.d.ts → buildSignedMobileRequest-BR-KJhIF.d.ts} +2 -2
  24. package/dist/{buildSignedMobileRequest-Cb1T74xV.d.ts.map → buildSignedMobileRequest-BR-KJhIF.d.ts.map} +1 -1
  25. package/dist/{buildSignedMobileRequest-NHbMAPzd.d.cts → buildSignedMobileRequest-DyKCK34Y.d.cts} +2 -2
  26. package/dist/{buildSignedMobileRequest-NHbMAPzd.d.cts.map → buildSignedMobileRequest-DyKCK34Y.d.cts.map} +1 -1
  27. package/dist/{canonicalize-BBYGh17w.d.ts → canonicalize-Bv6UIAbR.d.ts} +2 -2
  28. package/dist/canonicalize-Bv6UIAbR.d.ts.map +1 -0
  29. package/dist/{canonicalize-BF_SiNvO.d.cts → canonicalize-CWh3XZzj.d.cts} +2 -2
  30. package/dist/canonicalize-CWh3XZzj.d.cts.map +1 -0
  31. package/dist/clientTypes-BUn5_OzK.d.ts +1665 -0
  32. package/dist/clientTypes-BUn5_OzK.d.ts.map +1 -0
  33. package/dist/clientTypes-DOpUcu80.d.cts +1665 -0
  34. package/dist/clientTypes-DOpUcu80.d.cts.map +1 -0
  35. package/dist/dataMappers.cjs +691 -14
  36. package/dist/dataMappers.cjs.map +1 -1
  37. package/dist/dataMappers.d.cts +254 -8
  38. package/dist/dataMappers.d.cts.map +1 -1
  39. package/dist/dataMappers.d.ts +254 -8
  40. package/dist/dataMappers.d.ts.map +1 -1
  41. package/dist/dataMappers.js +651 -15
  42. package/dist/dataMappers.js.map +1 -1
  43. package/dist/{eip712MethodByType-BSx11xG-.d.cts → eip712MethodByType-CJ6BoayT.d.cts} +2 -2
  44. package/dist/eip712MethodByType-CJ6BoayT.d.cts.map +1 -0
  45. package/dist/{eip712MethodByType-DkiAjCLs.d.ts → eip712MethodByType-Dx4mvgni.d.ts} +2 -2
  46. package/dist/eip712MethodByType-Dx4mvgni.d.ts.map +1 -0
  47. package/dist/{feed-DTJlsg8W.d.ts → feed-DErOLaoY.d.cts} +4 -2
  48. package/dist/feed-DErOLaoY.d.cts.map +1 -0
  49. package/dist/{feed-DTJlsg8W.d.cts → feed-DErOLaoY.d.ts} +4 -2
  50. package/dist/feed-DErOLaoY.d.ts.map +1 -0
  51. package/dist/index.cjs +9 -2
  52. package/dist/index.d.cts +15 -16
  53. package/dist/index.d.ts +15 -16
  54. package/dist/index.js +5 -3
  55. package/dist/{mobileErrorCodes-3LtreeZM.d.ts → mobileErrorCodes-vD6rbFuF.d.cts} +25 -6
  56. package/dist/mobileErrorCodes-vD6rbFuF.d.cts.map +1 -0
  57. package/dist/{mobileErrorCodes-3LtreeZM.d.cts → mobileErrorCodes-vD6rbFuF.d.ts} +25 -6
  58. package/dist/mobileErrorCodes-vD6rbFuF.d.ts.map +1 -0
  59. package/dist/{payloadHash-BOWGjqdb.d.cts → payloadHash-CdkF2Ocr.d.cts} +2 -2
  60. package/dist/payloadHash-CdkF2Ocr.d.cts.map +1 -0
  61. package/dist/{payloadHash-Bzf4CtjV.d.ts → payloadHash-HD29K77M.d.ts} +2 -2
  62. package/dist/payloadHash-HD29K77M.d.ts.map +1 -0
  63. package/dist/serverExecuteTypes-5JyyIXRK.d.ts +178 -0
  64. package/dist/serverExecuteTypes-5JyyIXRK.d.ts.map +1 -0
  65. package/dist/serverExecuteTypes-CHrQ9Rtq.d.cts +178 -0
  66. package/dist/serverExecuteTypes-CHrQ9Rtq.d.cts.map +1 -0
  67. package/dist/serverModelTypes-CGUZCi0y.d.cts +938 -0
  68. package/dist/serverModelTypes-CGUZCi0y.d.cts.map +1 -0
  69. package/dist/serverModelTypes-CGUZCi0y.d.ts +938 -0
  70. package/dist/serverModelTypes-CGUZCi0y.d.ts.map +1 -0
  71. package/dist/{serverResponseGuards-BU1Xv_tG.d.ts → serverResponseGuards-Bvw8ltYJ.d.ts} +2 -2
  72. package/dist/{serverResponseGuards-BU1Xv_tG.d.ts.map → serverResponseGuards-Bvw8ltYJ.d.ts.map} +1 -1
  73. package/dist/{serverResponseGuards-Dkdok0Sm.d.cts → serverResponseGuards-i1njcYKN.d.cts} +2 -2
  74. package/dist/{serverResponseGuards-Dkdok0Sm.d.cts.map → serverResponseGuards-i1njcYKN.d.cts.map} +1 -1
  75. package/dist/signing/buildSignedMobileRequest.d.cts +1 -1
  76. package/dist/signing/buildSignedMobileRequest.d.ts +1 -1
  77. package/dist/signing/canonicalize.cjs +86 -0
  78. package/dist/signing/canonicalize.cjs.map +1 -1
  79. package/dist/signing/canonicalize.d.cts +1 -1
  80. package/dist/signing/canonicalize.d.ts +1 -1
  81. package/dist/signing/canonicalize.js +86 -0
  82. package/dist/signing/canonicalize.js.map +1 -1
  83. package/dist/signing/eip712MethodByType.cjs +12 -0
  84. package/dist/signing/eip712MethodByType.cjs.map +1 -1
  85. package/dist/signing/eip712MethodByType.d.cts +1 -1
  86. package/dist/signing/eip712MethodByType.d.ts +1 -1
  87. package/dist/signing/eip712MethodByType.js +12 -0
  88. package/dist/signing/eip712MethodByType.js.map +1 -1
  89. package/dist/signing/index.d.cts +5 -5
  90. package/dist/signing/index.d.ts +5 -5
  91. package/dist/signing/payloadHash.cjs +1 -1
  92. package/dist/signing/payloadHash.d.cts +1 -1
  93. package/dist/signing/payloadHash.d.ts +1 -1
  94. package/dist/signing/payloadHash.js +1 -1
  95. package/dist/signing/types.d.cts +1 -1
  96. package/dist/signing/types.d.ts +1 -1
  97. package/dist/types/MobileServerFailureError.d.cts +1 -1
  98. package/dist/types/MobileServerFailureError.d.ts +1 -1
  99. package/dist/types/MobileUnsupportedFeedItemError.cjs +19 -0
  100. package/dist/types/MobileUnsupportedFeedItemError.cjs.map +1 -0
  101. package/dist/types/MobileUnsupportedFeedItemError.d.cts +2 -0
  102. package/dist/types/MobileUnsupportedFeedItemError.d.ts +2 -0
  103. package/dist/types/MobileUnsupportedFeedItemError.js +18 -0
  104. package/dist/types/MobileUnsupportedFeedItemError.js.map +1 -0
  105. package/dist/types/MobileUnsupportedNotificationRouteError.cjs +19 -0
  106. package/dist/types/MobileUnsupportedNotificationRouteError.cjs.map +1 -0
  107. package/dist/types/MobileUnsupportedNotificationRouteError.d.cts +2 -0
  108. package/dist/types/MobileUnsupportedNotificationRouteError.d.ts +2 -0
  109. package/dist/types/MobileUnsupportedNotificationRouteError.js +18 -0
  110. package/dist/types/MobileUnsupportedNotificationRouteError.js.map +1 -0
  111. package/dist/types/clientTypes.d.cts +2 -2
  112. package/dist/types/clientTypes.d.ts +2 -2
  113. package/dist/types/index.cjs +6 -0
  114. package/dist/types/index.d.cts +9 -9
  115. package/dist/types/index.d.ts +9 -9
  116. package/dist/types/index.js +4 -2
  117. package/dist/types/mobileErrorCodes.cjs +39 -1
  118. package/dist/types/mobileErrorCodes.cjs.map +1 -1
  119. package/dist/types/mobileErrorCodes.d.cts +1 -1
  120. package/dist/types/mobileErrorCodes.d.ts +1 -1
  121. package/dist/types/mobileErrorCodes.js +39 -1
  122. package/dist/types/mobileErrorCodes.js.map +1 -1
  123. package/dist/types/serverBaseTypes.d.cts +1 -1
  124. package/dist/types/serverBaseTypes.d.ts +1 -1
  125. package/dist/types/serverExecuteTypes.d.cts +2 -2
  126. package/dist/types/serverExecuteTypes.d.ts +2 -2
  127. package/dist/types/serverModelTypes.cjs +15 -0
  128. package/dist/types/serverModelTypes.cjs.map +1 -1
  129. package/dist/types/serverModelTypes.d.cts +2 -2
  130. package/dist/types/serverModelTypes.d.ts +2 -2
  131. package/dist/types/serverModelTypes.js +14 -1
  132. package/dist/types/serverModelTypes.js.map +1 -1
  133. package/dist/types/serverQueryTypes.d.cts +2 -2
  134. package/dist/types/serverQueryTypes.d.ts +2 -2
  135. package/dist/types/serverRequestTypes.d.cts +2 -2
  136. package/dist/types/serverRequestTypes.d.ts +2 -2
  137. package/dist/types-C9YE4EIt.d.cts +794 -0
  138. package/dist/types-C9YE4EIt.d.cts.map +1 -0
  139. package/dist/types-Cwy1y_9x.d.ts +794 -0
  140. package/dist/types-Cwy1y_9x.d.ts.map +1 -0
  141. package/dist/utils/buildMobileFeedImageMultipart.cjs +31 -0
  142. package/dist/utils/buildMobileFeedImageMultipart.cjs.map +1 -0
  143. package/dist/utils/buildMobileFeedImageMultipart.d.cts +15 -0
  144. package/dist/utils/buildMobileFeedImageMultipart.d.cts.map +1 -0
  145. package/dist/utils/buildMobileFeedImageMultipart.d.ts +15 -0
  146. package/dist/utils/buildMobileFeedImageMultipart.d.ts.map +1 -0
  147. package/dist/utils/buildMobileFeedImageMultipart.js +30 -0
  148. package/dist/utils/buildMobileFeedImageMultipart.js.map +1 -0
  149. package/dist/utils/feed.cjs +3 -0
  150. package/dist/utils/feed.cjs.map +1 -1
  151. package/dist/utils/feed.d.cts +2 -2
  152. package/dist/utils/feed.d.ts +2 -2
  153. package/dist/utils/feed.js +3 -1
  154. package/dist/utils/feed.js.map +1 -1
  155. package/dist/utils/index.cjs +2 -1
  156. package/dist/utils/index.d.cts +3 -3
  157. package/dist/utils/index.d.ts +3 -3
  158. package/dist/utils/index.js +2 -2
  159. package/dist/utils/serverResponseGuards.d.cts +1 -1
  160. package/dist/utils/serverResponseGuards.d.ts +1 -1
  161. package/package.json +3 -3
  162. package/src/MobileClient.ts +789 -7
  163. package/src/dataMappers.test.ts +848 -0
  164. package/src/dataMappers.ts +924 -17
  165. package/src/feedImages.test.ts +309 -0
  166. package/src/notifications.test.ts +950 -0
  167. package/src/signing/canonicalize.ts +119 -0
  168. package/src/signing/eip712MethodByType.ts +15 -0
  169. package/src/signing/signing.test.ts +362 -0
  170. package/src/signing/types.ts +108 -13
  171. package/src/socialFeed.test.ts +38 -2
  172. package/src/types/MobileUnsupportedFeedItemError.ts +18 -0
  173. package/src/types/MobileUnsupportedNotificationRouteError.ts +16 -0
  174. package/src/types/clientTypes.ts +1012 -34
  175. package/src/types/index.ts +2 -0
  176. package/src/types/mobileErrorCodes.ts +38 -0
  177. package/src/types/serverExecuteTypes.ts +112 -3
  178. package/src/types/serverModelTypes.ts +581 -28
  179. package/src/types/serverQueryTypes.ts +212 -5
  180. package/src/types/serverRequestTypes.ts +213 -13
  181. package/src/utils/buildMobileFeedImageMultipart.test.ts +45 -0
  182. package/src/utils/buildMobileFeedImageMultipart.ts +36 -0
  183. package/src/utils/feed.ts +3 -0
  184. package/dist/MobileClient-aDxiM_Kf.cjs +0 -562
  185. package/dist/MobileClient-aDxiM_Kf.cjs.map +0 -1
  186. package/dist/MobileServerFailureError-Bpa_WA9f.d.cts.map +0 -1
  187. package/dist/MobileServerFailureError-Dd3c6P_Z.d.ts.map +0 -1
  188. package/dist/canonicalize-BBYGh17w.d.ts.map +0 -1
  189. package/dist/canonicalize-BF_SiNvO.d.cts.map +0 -1
  190. package/dist/clientTypes-BWFKo9oE.d.cts +0 -844
  191. package/dist/clientTypes-BWFKo9oE.d.cts.map +0 -1
  192. package/dist/clientTypes-DCTiUV0H.d.ts +0 -844
  193. package/dist/clientTypes-DCTiUV0H.d.ts.map +0 -1
  194. package/dist/eip712MethodByType-BSx11xG-.d.cts.map +0 -1
  195. package/dist/eip712MethodByType-DkiAjCLs.d.ts.map +0 -1
  196. package/dist/feed-DTJlsg8W.d.cts.map +0 -1
  197. package/dist/feed-DTJlsg8W.d.ts.map +0 -1
  198. package/dist/mobileErrorCodes-3LtreeZM.d.cts.map +0 -1
  199. package/dist/mobileErrorCodes-3LtreeZM.d.ts.map +0 -1
  200. package/dist/payloadHash-BOWGjqdb.d.cts.map +0 -1
  201. package/dist/payloadHash-Bzf4CtjV.d.ts.map +0 -1
  202. package/dist/serverBaseTypes-DWf3iGWy.d.ts +0 -25
  203. package/dist/serverBaseTypes-DWf3iGWy.d.ts.map +0 -1
  204. package/dist/serverBaseTypes-KREDe2M9.d.cts +0 -25
  205. package/dist/serverBaseTypes-KREDe2M9.d.cts.map +0 -1
  206. package/dist/serverExecuteTypes-DVRa6ifu.d.cts +0 -89
  207. package/dist/serverExecuteTypes-DVRa6ifu.d.cts.map +0 -1
  208. package/dist/serverExecuteTypes-DlYZCp1f.d.ts +0 -89
  209. package/dist/serverExecuteTypes-DlYZCp1f.d.ts.map +0 -1
  210. package/dist/serverModelTypes-DAqEyYtB.d.cts +0 -508
  211. package/dist/serverModelTypes-DAqEyYtB.d.cts.map +0 -1
  212. package/dist/serverModelTypes-DAqEyYtB.d.ts +0 -508
  213. package/dist/serverModelTypes-DAqEyYtB.d.ts.map +0 -1
  214. package/dist/serverQueryTypes-BFdwq0Z2.d.ts +0 -171
  215. package/dist/serverQueryTypes-BFdwq0Z2.d.ts.map +0 -1
  216. package/dist/serverQueryTypes-DNdMpmDr.d.cts +0 -171
  217. package/dist/serverQueryTypes-DNdMpmDr.d.cts.map +0 -1
  218. package/dist/serverRequestTypes-BNA7FCY6.d.ts +0 -200
  219. package/dist/serverRequestTypes-BNA7FCY6.d.ts.map +0 -1
  220. package/dist/serverRequestTypes-CxDRFKfv.d.cts +0 -200
  221. package/dist/serverRequestTypes-CxDRFKfv.d.cts.map +0 -1
  222. package/dist/types-BCr2G5gS.d.cts +0 -84
  223. package/dist/types-BCr2G5gS.d.cts.map +0 -1
  224. package/dist/types-C18k-9Vy.d.ts +0 -84
  225. package/dist/types-C18k-9Vy.d.ts.map +0 -1
@@ -5,6 +5,7 @@ import {
5
5
  WalletNotProvidedError,
6
6
  } from '@nadohq/shared';
7
7
  import axios, { AxiosInstance, AxiosResponse } from 'axios';
8
+ import { bytesToString, keccak256, zeroHash } from 'viem';
8
9
  import {
9
10
  mapMobileAvatarPreset,
10
11
  mapMobileAvatarSelectionToServer,
@@ -14,29 +15,58 @@ import {
14
15
  mapMobileFollowListPage,
15
16
  mapMobileFollowListParamsToServer,
16
17
  mapMobileFollowMutationResult,
18
+ mapMobileNotificationCapabilitiesToServer,
19
+ mapMobileNotificationInboxV2,
17
20
  mapMobileNotificationPreferences,
18
21
  mapMobileNotificationPreferencesToServer,
22
+ mapMobileNotificationRegistrationV2,
23
+ mapMobileNotificationSettingsToServer,
24
+ mapMobileNotificationSettingsV2,
25
+ mapMobileNotificationSubscriptions,
26
+ mapMobileNotificationSubscriptionsUpdateToServer,
27
+ mapMobileProductEventToServer,
19
28
  mapMobileProfileSearchPage,
20
29
  mapMobileProfileSearchParamsToServer,
21
30
  mapMobileProfilesIncludeToServer,
22
31
  mapMobilePublicProfile,
23
32
  mapMobileRegisteredWallet,
33
+ mapMobileSocialFeedActionResolutionResult,
34
+ mapMobileSocialFeedCommentResult,
35
+ mapMobileSocialFeedCommentsPage,
36
+ mapMobileSocialFeedDrawingMutationResult,
37
+ mapMobileSocialFeedDrawingResult,
38
+ mapMobileSocialFeedImage,
39
+ mapMobileSocialFeedItem,
24
40
  mapMobileSocialFeedItemResponse,
41
+ mapMobileSocialFeedLikeResult,
25
42
  mapMobileSocialFeedListParamsToServer,
43
+ mapMobileSocialFeedMentionToServer,
26
44
  mapMobileSocialFeedPage,
45
+ mapMobileSocialFeedPositionChart,
46
+ mapMobileSocialFeedPositionHistory,
47
+ mapMobileSocialFeedPositionResolutionResult,
48
+ mapMobileSocialFeedPositionsPage,
49
+ mapMobileSocialFeedPresence,
27
50
  mapMobileSocialFeedRankedPage,
28
51
  mapMobileSocialFeedReadParamsToServer,
29
52
  mapMobileSocialFeedTopTradersPage,
30
53
  mapMobileSocialFeedUpdates,
54
+ mapMobileSocialFeedViewsResult,
55
+ mapMobileSocialFeedWatchers,
31
56
  } from './dataMappers';
32
57
  import {
33
58
  buildSignedMobileRequest,
59
+ getMobileNonce,
34
60
  MobileSignedInner,
35
61
  MobileSignedInnerByType,
36
62
  MobileSignedInnerParams,
37
63
  MobileSignedRequest,
38
64
  } from './signing';
39
65
  import {
66
+ GetMobileFeedChartDrawingParams,
67
+ GetMobileFeedCommentsParams,
68
+ GetMobileFeedImageBytesParams,
69
+ GetMobileFeedImageRequestParams,
40
70
  GetMobileFeedItemParams,
41
71
  GetMobileFeedParams,
42
72
  GetMobileFeedUpdatesParams,
@@ -45,40 +75,81 @@ import {
45
75
  GetMobileForYouFeedParams,
46
76
  GetMobileFriendsFeedParams,
47
77
  GetMobileMarketFeedParams,
78
+ GetMobileNotificationInboxV2Params,
48
79
  GetMobileNotificationPreferencesParams,
80
+ GetMobileNotificationRegistrationV2Params,
81
+ GetMobileNotificationSettingsV2Params,
82
+ GetMobileNotificationSubscriptionsParams,
83
+ GetMobilePositionChartParams,
49
84
  GetMobilePositionFeedParams,
85
+ GetMobilePositionHistoryParams,
86
+ GetMobilePositionWatchersParams,
50
87
  GetMobileProfileFeedParams,
51
88
  GetMobileProfilesParams,
52
89
  GetMobileRegisteredWalletParams,
90
+ GetMobileSelfFeedPositionsParams,
53
91
  GetMobileTopTradersFeedParams,
54
92
  GetMobileUsernameAvailabilityParams,
55
93
  MobileAvatarPreset,
56
94
  MobileAvatarUpload,
57
95
  MobileCreateAvatarUploadParams,
96
+ MobileCreateFeedCommentParams,
97
+ MobileCreateFeedImageUploadParams,
98
+ MobileCreateFeedPostParams,
99
+ MobileFeedChartDrawingParams,
100
+ MobileFeedImageRequest,
58
101
  MobileFeedPage,
59
102
  MobileFollowBatchResultItem,
60
103
  MobileFollowListPage,
61
104
  MobileFollowMutationResult,
105
+ MobileNotificationInboxV2,
62
106
  MobileNotificationPreferences,
107
+ MobileNotificationRegistrationV2,
108
+ MobileNotificationSettingsV2,
109
+ MobileNotificationSubscriptions,
110
+ MobilePositionPresenceParams,
63
111
  MobileProfileSearchPage,
64
112
  MobilePublicProfile,
113
+ MobileRecordFeedViewsParams,
114
+ MobileRecordProductEventsParams,
65
115
  MobileRegisteredWallet,
66
116
  MobileRegisterExpoTokenParams,
117
+ MobileRegisterExpoTokenV2Params,
67
118
  MobileSetAvatarParams,
68
119
  MobileSetBioParams,
120
+ MobileSetFeedLikeParams,
69
121
  MobileSetFollowBatchParams,
70
122
  MobileSetFollowParams,
71
123
  MobileSetPrivateModeParams,
72
124
  MobileSetUsernameParams,
73
125
  MobileSignedRequestParams,
126
+ MobileSocialFeedActionResolutionResult,
127
+ MobileSocialFeedCommentResult,
128
+ MobileSocialFeedCommentsPage,
129
+ MobileSocialFeedDrawingMutationResult,
130
+ MobileSocialFeedDrawingResult,
131
+ MobileSocialFeedImage,
132
+ MobileSocialFeedItem,
74
133
  MobileSocialFeedItemResponse,
134
+ MobileSocialFeedLikeResult,
75
135
  MobileSocialFeedPage,
136
+ MobileSocialFeedPositionChart,
137
+ MobileSocialFeedPositionHistory,
138
+ MobileSocialFeedPositionResolutionResult,
139
+ MobileSocialFeedPositionsPage,
140
+ MobileSocialFeedPresence,
76
141
  MobileSocialFeedRankedPage,
77
142
  MobileSocialFeedTopTradersPage,
78
143
  MobileSocialFeedUpdates,
144
+ MobileSocialFeedViewsResult,
145
+ MobileSocialFeedWatchers,
79
146
  MobileUnregisterExpoTokenParams,
80
147
  MobileUpdateNotificationPreferencesParams,
148
+ MobileUpdateNotificationSettingsV2Params,
149
+ MobileUpdateNotificationSubscriptionsParams,
81
150
  MobileUsernameAvailability,
151
+ ResolveMobileFeedActionParams,
152
+ ResolveMobileFeedPositionParams,
82
153
  SearchMobileProfilesParams,
83
154
  } from './types/clientTypes';
84
155
  import { MobileServerFailureError } from './types/MobileServerFailureError';
@@ -87,16 +158,23 @@ import {
87
158
  MobileServerExecuteResult,
88
159
  MobileServerExecuteSuccessResponse,
89
160
  MobileServerPublicExecuteRequest,
161
+ MobileServerPublicExecuteSuccessResponse,
90
162
  } from './types/serverExecuteTypes';
91
163
  import {
92
164
  MobileServerPublicQueryRequest,
93
165
  MobileServerPublicQuerySuccessResponse,
166
+ MobileServerSignedQuerySuccessResponse,
94
167
  } from './types/serverQueryTypes';
95
168
  import {
96
169
  MobileServerExecuteRequestType,
170
+ MobileServerPublicExecuteRequestByType,
171
+ MobileServerPublicExecuteRequestType,
97
172
  MobileServerPublicQueryRequestByType,
98
173
  MobileServerPublicQueryRequestType,
174
+ MobileServerSignedQueryRequestType,
99
175
  } from './types/serverRequestTypes';
176
+ import { buildMobileFeedImageMultipart } from './utils/buildMobileFeedImageMultipart';
177
+ import { MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES } from './utils/feed';
100
178
  import {
101
179
  isMobileServerFailureResponse,
102
180
  isMobileServerSuccessResponse,
@@ -312,6 +390,7 @@ export class MobileClient {
312
390
  * @param params - Filters, pagination, optional viewing account, and browser credential; no signing identity.
313
391
  * @returns A fixed-session page with its ranking version and new-content watermark.
314
392
  * @throws {MobileServerFailureError} On invalid parameters, session mismatch/expiry, or unavailable data.
393
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
315
394
  */
316
395
  async getForYouFeed(
317
396
  params: GetMobileForYouFeedParams = {},
@@ -332,6 +411,7 @@ export class MobileClient {
332
411
  * @param params - Filters, pagination, optional viewing account, and browser credential.
333
412
  * @returns A page with its qualification cohort; an unavailable cohort fails instead of returning an empty ranking.
334
413
  * @throws {MobileServerFailureError} On request/session errors or unavailable cohort data.
414
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
335
415
  */
336
416
  async getTopTradersFeed(
337
417
  params: GetMobileTopTradersFeedParams = {},
@@ -351,6 +431,7 @@ export class MobileClient {
351
431
  * @param params - Required viewing account on every request, filters, pagination, and browser credential.
352
432
  * @returns A chronological Friends page and reading session.
353
433
  * @throws {MobileServerFailureError} On invalid viewing account, session errors, or feed query failure.
434
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
354
435
  */
355
436
  async getFriendsFeed(
356
437
  params: GetMobileFriendsFeedParams,
@@ -371,6 +452,7 @@ export class MobileClient {
371
452
  * @param params - Target identity, filters, pagination, and optional public viewing account.
372
453
  * @returns An author page without main-feed ranking or cohort fields.
373
454
  * @throws {MobileServerFailureError} On invalid parameters, session errors, or inaccessible content.
455
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
374
456
  */
375
457
  async getProfileFeed(
376
458
  params: GetMobileProfileFeedParams,
@@ -391,6 +473,7 @@ export class MobileClient {
391
473
  * @param params - Product ID, content/size filters, pagination, and public viewing account.
392
474
  * @returns A market page without main-feed ranking fields.
393
475
  * @throws {MobileServerFailureError} On an unknown market, session errors, or unavailable data.
476
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
394
477
  */
395
478
  async getMarketFeed(
396
479
  params: GetMobileMarketFeedParams,
@@ -411,6 +494,7 @@ export class MobileClient {
411
494
  * @param params - Position UUID, filters, pagination, and public viewing account.
412
495
  * @returns A fixed-session position feed page.
413
496
  * @throws {MobileServerFailureError} On inaccessible content, session errors, or unavailable data.
497
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
414
498
  */
415
499
  async getPositionFeed(
416
500
  params: GetMobilePositionFeedParams,
@@ -428,9 +512,12 @@ export class MobileClient {
428
512
  /**
429
513
  * Reads one item visible to viewAs, including that account's own hidden content.
430
514
  * Creates an item session directly when sessionId is omitted.
431
- * @param params - Item UUID, preview limit, and optional existing session/read identity.
515
+ * Pass {@link GetMobileFeedItemParams.viewEventId} when the user navigates into the detail so the
516
+ * subsequent {@link recordFeedViews} call can count that visit; omit it for prefetch.
517
+ * @param params - Item UUID, optional detail-visit event, preview limit, and optional existing session/read identity.
432
518
  * @returns The complete item and authorized reading session.
433
519
  * @throws {MobileServerFailureError} On inaccessible content or session mismatch/expiry.
520
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
434
521
  */
435
522
  async getFeedItem(
436
523
  params: GetMobileFeedItemParams,
@@ -438,6 +525,7 @@ export class MobileClient {
438
525
  const body: MobileServerPublicQueryRequest<'feed_item'> = {
439
526
  type: 'feed_item',
440
527
  item_id: params.itemId,
528
+ view_event_id: params.viewEventId,
441
529
  comment_preview_limit: params.commentPreviewLimit,
442
530
  session_id: params.sessionId,
443
531
  ...mapMobileSocialFeedReadParamsToServer(params),
@@ -481,6 +569,7 @@ export class MobileClient {
481
569
  *
482
570
  * @throws {MobileServerFailureError} With error code `INVALID_EXPO_TOKEN` if the token is malformed, or is
483
571
  * not currently registered to a wallet.
572
+ * @deprecated Use {@link getNotificationSettingsV2} instead.
484
573
  */
485
574
  async getNotificationPreferences(
486
575
  params: GetMobileNotificationPreferencesParams,
@@ -514,6 +603,302 @@ export class MobileClient {
514
603
  return mapMobileRegisteredWallet(data);
515
604
  }
516
605
 
606
+ /**
607
+ * Lists a selected account's current positions without signing or authenticating ownership.
608
+ * Publication and attachment eligibility are hints that the service rechecks on writes.
609
+ * @param params - Viewing subaccount, optional market filter, page size, and opaque cursor.
610
+ * @returns Current position candidates, their eligibility hints, the next cursor, and observation time.
611
+ * @throws {MobileServerFailureError} On invalid parameters, an unsupported viewing account, or unavailable
612
+ * position data. An account with no open positions returns an empty page instead of an error.
613
+ */
614
+ async getSelfFeedPositions(
615
+ params: GetMobileSelfFeedPositionsParams,
616
+ ): Promise<MobileSocialFeedPositionsPage> {
617
+ const body: MobileServerPublicQueryRequest<'self_feed_positions'> = {
618
+ type: 'self_feed_positions',
619
+ view_as: subaccountToHex(params.viewAs),
620
+ product_id: params.productId,
621
+ cursor: params.cursor,
622
+ limit: params.limit,
623
+ };
624
+ return mapMobileSocialFeedPositionsPage(await this.publicQuery(body));
625
+ }
626
+
627
+ /**
628
+ * Resolves a slash command against a selected account without changing the caller's input.
629
+ * @param params - Viewing subaccount, original command text, and optional market disambiguation.
630
+ * @returns The resolution, nullable market, candidate positions, and reason for an empty result.
631
+ * @throws {MobileServerFailureError} On invalid parameters, an unsupported viewing account, or unavailable
632
+ * source data. Unknown markets and accounts without open positions are normal resolution results.
633
+ */
634
+ async resolveFeedPosition(
635
+ params: ResolveMobileFeedPositionParams,
636
+ ): Promise<MobileSocialFeedPositionResolutionResult> {
637
+ const body: MobileServerPublicQueryRequest<'resolve_feed_position'> = {
638
+ type: 'resolve_feed_position',
639
+ view_as: subaccountToHex(params.viewAs),
640
+ input: params.input,
641
+ product_id: params.productId,
642
+ };
643
+ return mapMobileSocialFeedPositionResolutionResult(
644
+ await this.publicQuery(body),
645
+ );
646
+ }
647
+
648
+ /**
649
+ * Resolves every trusted lifecycle segment of an order without requiring a signature.
650
+ * @param params - Order-owning subaccount and order digest; selecting the account is not authentication.
651
+ * @returns Trusted action candidates and their observation time, or a pending result with no actions.
652
+ * @throws {MobileServerFailureError} On invalid parameters, an inaccessible order, or unavailable source
653
+ * data. Pending projection is a successful result, not a source failure.
654
+ */
655
+ async resolveFeedAction(
656
+ params: ResolveMobileFeedActionParams,
657
+ ): Promise<MobileSocialFeedActionResolutionResult> {
658
+ const body: MobileServerPublicQueryRequest<'resolve_feed_action'> = {
659
+ type: 'resolve_feed_action',
660
+ view_as: subaccountToHex(params.viewAs),
661
+ order_digest: params.orderDigest,
662
+ };
663
+ return mapMobileSocialFeedActionResolutionResult(
664
+ await this.publicQuery(body),
665
+ );
666
+ }
667
+
668
+ /**
669
+ * Reads a drawing publicly without issuing a reading session. Supplied sessions retain their scope.
670
+ * @param params - Parent item, optional viewing account, and optional original session and viewer token.
671
+ * @returns The parent ID and version, with a nullable drawing whose data may legitimately be false or zero.
672
+ * @throws {MobileServerFailureError} On invalid parameters, session mismatch or expiry, unavailable data,
673
+ * or `SOCIAL_FEED_DRAWING_UNAVAILABLE` when the parent is inaccessible. A readable parent without a drawing
674
+ * returns null. Acquire a new reading session when the original has expired.
675
+ */
676
+ async getFeedChartDrawing(
677
+ params: GetMobileFeedChartDrawingParams,
678
+ ): Promise<MobileSocialFeedDrawingResult> {
679
+ const body: MobileServerPublicQueryRequest<'feed_chart_drawing'> = {
680
+ type: 'feed_chart_drawing',
681
+ item_id: params.itemId,
682
+ session_id: params.sessionId,
683
+ ...mapMobileSocialFeedReadParamsToServer(params),
684
+ };
685
+ return mapMobileSocialFeedDrawingResult(await this.publicQuery(body));
686
+ }
687
+
688
+ /**
689
+ * Resolves a backend feed image path against this client's mobile gateway URL.
690
+ * @param path - Backend path from image metadata, rooted at /v1/mobile or the mobile service root.
691
+ * @returns An absolute URL suitable for authenticated fetches.
692
+ */
693
+ resolveFeedImageUrl(path: string): string {
694
+ return `${this.opts.url}${path.replace(/^\/v1\/mobile(?=\/)/, '')}`;
695
+ }
696
+
697
+ /**
698
+ * Prepares a protected image request for native image components without downloading or encoding bytes.
699
+ * Does not count as a detail visit or recorded view.
700
+ * @param params - Image path from metadata plus the original session credentials.
701
+ * @returns Absolute URL and headers; pass them as the image source's URI and headers.
702
+ */
703
+ getFeedImageRequest(
704
+ params: GetMobileFeedImageRequestParams,
705
+ ): MobileFeedImageRequest {
706
+ return {
707
+ url: this.resolveFeedImageUrl(params.path),
708
+ headers: {
709
+ 'x-feed-session-id': params.sessionId,
710
+ 'x-feed-viewer-token': params.viewerToken,
711
+ },
712
+ };
713
+ }
714
+
715
+ /**
716
+ * Fetches protected feed image bytes using the reading session that fully delivered the parent item.
717
+ * Does not count as a detail visit or recorded view.
718
+ * @param params - Image path from metadata plus the original session credentials.
719
+ * @returns Raw image bytes.
720
+ * @throws {MobileServerFailureError} On session, permission, or availability errors.
721
+ */
722
+ async getFeedImageBytes(
723
+ params: GetMobileFeedImageBytesParams,
724
+ ): Promise<Uint8Array> {
725
+ const { url, headers } = this.getFeedImageRequest(params);
726
+ return this.publicGetBytes(url, headers);
727
+ }
728
+
729
+ /**
730
+ * Reads a comment thread with an optional anchor and bidirectional pagination.
731
+ * Independent reads create a public-only session; reused sessions retain their original scope.
732
+ * @param params - Root item, optional anchor or cursor (mutually exclusive), page size, and read perspective.
733
+ * Paging requires the original session and viewer token.
734
+ * @returns Replies, total count, forward and backward cursors, the anchor, and the actual reading session.
735
+ * @throws {MobileServerFailureError} On invalid parameters, session mismatch or expiry, inaccessible content,
736
+ * or unavailable data. Restart pagination with a new session after expiry; do not reuse the old cursor.
737
+ */
738
+ async getFeedComments(
739
+ params: GetMobileFeedCommentsParams,
740
+ ): Promise<MobileSocialFeedCommentsPage> {
741
+ const body: MobileServerPublicQueryRequest<'feed_comments'> = {
742
+ type: 'feed_comments',
743
+ root_item_id: params.rootItemId,
744
+ cursor: params.cursor,
745
+ limit: params.limit,
746
+ anchor_reply_id: params.anchorReplyId,
747
+ session_id: params.sessionId,
748
+ ...mapMobileSocialFeedReadParamsToServer(params),
749
+ };
750
+ return mapMobileSocialFeedCommentsPage(await this.publicQuery(body));
751
+ }
752
+
753
+ /**
754
+ * Reads the full position lifecycle and creates or reuses a position session.
755
+ * Unlike getPositionFeed, this includes lifecycle actions as well as published takes.
756
+ * @param params - Position, optional takes-only filter, pagination, and read perspective. Paging requires
757
+ * the original position session and viewer token, not a feed session.
758
+ * @returns Position metrics, ordered action/take history, summary, trading hints, cursor, and reading session.
759
+ * @throws {MobileServerFailureError} On invalid parameters, session mismatch or expiry, inaccessible content,
760
+ * or unavailable source data. Restart with a new position session after expiry.
761
+ * @throws {MobileUnsupportedFeedItemError} If a timeline entry or take has an unsupported kind.
762
+ */
763
+ async getPositionHistory(
764
+ params: GetMobilePositionHistoryParams,
765
+ ): Promise<MobileSocialFeedPositionHistory> {
766
+ const body: MobileServerPublicQueryRequest<'position_history'> = {
767
+ type: 'position_history',
768
+ position_id: params.positionId,
769
+ takes_only: params.takesOnly,
770
+ cursor: params.cursor,
771
+ limit: params.limit,
772
+ session_id: params.sessionId,
773
+ ...mapMobileSocialFeedReadParamsToServer(params),
774
+ };
775
+ return mapMobileSocialFeedPositionHistory(await this.publicQuery(body));
776
+ }
777
+
778
+ /**
779
+ * Reads candles and action markers without creating a reading session.
780
+ * Preserve the original range, interval, and read perspective when paging with nextBeforeMs.
781
+ * @param params - Position, candle interval, half-open time range, pagination, and optional original session
782
+ * and viewer token. An independent read omits both session credentials.
783
+ * @returns Candles with decimal prices and x18 volume, action markers, a nullable liquidation line, and paging metadata.
784
+ * @throws {MobileServerFailureError} On invalid parameters, session mismatch or expiry, inaccessible content,
785
+ * or wholly unavailable chart sources. Partially available data is returned with its quality indicator.
786
+ */
787
+ async getPositionChart(
788
+ params: GetMobilePositionChartParams,
789
+ ): Promise<MobileSocialFeedPositionChart> {
790
+ const body: MobileServerPublicQueryRequest<'position_chart'> = {
791
+ type: 'position_chart',
792
+ position_id: params.positionId,
793
+ session_id: params.sessionId,
794
+ interval: params.interval,
795
+ range: { from_ms: params.range.fromMs, to_ms: params.range.toMs },
796
+ before_ms: params.beforeMs,
797
+ limit: params.limit,
798
+ ...mapMobileSocialFeedReadParamsToServer(params),
799
+ };
800
+ return mapMobileSocialFeedPositionChart(await this.publicQuery(body));
801
+ }
802
+
803
+ /**
804
+ * Reads active visitor counts and self-reported account previews without registering presence.
805
+ * @param params - Position and optional viewing account, used only for preview relationship information.
806
+ * @returns The visitor count, public account previews, and observation time; previews need not match the count.
807
+ * @throws {MobileServerFailureError} On invalid parameters, an unavailable position, or unavailable source data.
808
+ */
809
+ async getPositionWatchers(
810
+ params: GetMobilePositionWatchersParams,
811
+ ): Promise<MobileSocialFeedWatchers> {
812
+ const body: MobileServerPublicQueryRequest<'position_watchers'> = {
813
+ type: 'position_watchers',
814
+ position_id: params.positionId,
815
+ view_as:
816
+ params.viewAs === undefined
817
+ ? undefined
818
+ : subaccountToHex(params.viewAs),
819
+ };
820
+ return mapMobileSocialFeedWatchers(await this.publicQuery(body));
821
+ }
822
+
823
+ /**
824
+ * Reads the token's latest registration generation and saved capabilities, including legacy v1 registrations.
825
+ * @param params - Active Expo token credential; no wallet signature is needed.
826
+ * @returns Saved generation as an opaque string and the complete capability declaration.
827
+ * @throws {MobileServerFailureError} If the token is invalid or inactive (`INVALID_EXPO_TOKEN`).
828
+ */
829
+ async getNotificationRegistrationV2(
830
+ params: GetMobileNotificationRegistrationV2Params,
831
+ ): Promise<MobileNotificationRegistrationV2> {
832
+ return mapMobileNotificationRegistrationV2(
833
+ await this.publicQuery({
834
+ type: 'notification_registration_v2',
835
+ expo_token: params.expoToken,
836
+ }),
837
+ );
838
+ }
839
+
840
+ /**
841
+ * Reads the wallet's full v2 settings document, including legacy preference mappings.
842
+ * @param params - Active Expo token credential. Before displaying settings, compare the wallet returned by
843
+ * {@link MobileClient.getRegisteredWallet} with the connected wallet (case-insensitively).
844
+ * @returns CamelCase settings with the current settings revision.
845
+ * @throws {MobileServerFailureError} If the token is invalid or inactive (`INVALID_EXPO_TOKEN`).
846
+ */
847
+ async getNotificationSettingsV2(
848
+ params: GetMobileNotificationSettingsV2Params,
849
+ ): Promise<MobileNotificationSettingsV2> {
850
+ return mapMobileNotificationSettingsV2(
851
+ await this.publicQuery({
852
+ type: 'notification_settings_v2',
853
+ expo_token: params.expoToken,
854
+ }),
855
+ );
856
+ }
857
+
858
+ /*
859
+ Signed queries
860
+ */
861
+
862
+ /**
863
+ * Reads wallet market subscriptions and the signing Identity's enabled trader bells.
864
+ * @param params - Wallet authentication context; no Expo token is needed.
865
+ * @returns Subscriptions, import state, and the independent subscription revision.
866
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
867
+ * @throws {MobileServerFailureError} If authentication or the query fails.
868
+ */
869
+ async getNotificationSubscriptions(
870
+ params: GetMobileNotificationSubscriptionsParams,
871
+ ): Promise<MobileNotificationSubscriptions> {
872
+ const request = await this.getSignedRequest(
873
+ 'notification_subscriptions',
874
+ params,
875
+ {},
876
+ );
877
+ return mapMobileNotificationSubscriptions(await this.query(request));
878
+ }
879
+
880
+ /**
881
+ * Reads private accepted notification intents, not delivery receipts or read states.
882
+ * @param params - Wallet authentication and optional cursor/page size (1-50, default 20).
883
+ * @returns A camelCase page; discard cached pages and cursors when switching wallets.
884
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
885
+ * @throws {MobileServerFailureError} If authentication or pagination validation fails.
886
+ * @throws {MobileUnsupportedNotificationRouteError} If a notification has an unsupported route name.
887
+ */
888
+ async getNotificationInboxV2(
889
+ params: GetMobileNotificationInboxV2Params,
890
+ ): Promise<MobileNotificationInboxV2> {
891
+ const request = await this.getSignedRequest(
892
+ 'notification_inbox_v2',
893
+ params,
894
+ {
895
+ cursor: params.cursor ?? null,
896
+ limit: params.limit ?? null,
897
+ },
898
+ );
899
+ return mapMobileNotificationInboxV2(await this.query(request));
900
+ }
901
+
517
902
  /*
518
903
  Public executes
519
904
  */
@@ -549,6 +934,7 @@ export class MobileClient {
549
934
  *
550
935
  * @throws {MobileServerFailureError} With error code `INVALID_PREFERENCES` if those rules are violated, or
551
936
  * `INVALID_EXPO_TOKEN` if the token is malformed or is not currently registered to a wallet.
937
+ * @deprecated Use {@link updateNotificationSettingsV2} instead.
552
938
  */
553
939
  async updateNotificationPreferences(
554
940
  params: MobileUpdateNotificationPreferencesParams,
@@ -561,6 +947,82 @@ export class MobileClient {
561
947
  return this.publicExecute(body);
562
948
  }
563
949
 
950
+ /**
951
+ * Replaces all v2 settings fields using optimistic concurrency; legacy overlapping preferences are synced.
952
+ * @param params - Active Expo token, latest settings revision, and complete replacement settings.
953
+ * @returns The saved settings document with its incremented revision.
954
+ * @throws {MobileServerFailureError} On invalid token/settings or revision conflict (`NOTIFICATION_REVISION_CONFLICT`). Re-read and
955
+ * merge only the user's current change before retrying; never blindly replay a stale document.
956
+ */
957
+ async updateNotificationSettingsV2(
958
+ params: MobileUpdateNotificationSettingsV2Params,
959
+ ): Promise<MobileNotificationSettingsV2> {
960
+ return mapMobileNotificationSettingsV2(
961
+ await this.publicExecute({
962
+ type: 'update_notification_settings_v2',
963
+ expo_token: params.expoToken,
964
+ expected_revision: params.expectedRevision,
965
+ settings: mapMobileNotificationSettingsToServer(params.settings),
966
+ }),
967
+ );
968
+ }
969
+
970
+ /**
971
+ * Reports a detail visit without signing. Feed-list card impressions and previews do not count.
972
+ * After the primary detail target is shown in the foreground, send the same viewEventId previously
973
+ * registered through {@link getFeedItem}, together with that response's sessionId and viewerToken.
974
+ * Reuse the event ID on retries for the same visit; generate a new one only after leaving and re-entering.
975
+ * @param params - Original reading session and viewer token, the registered detail-visit event, and exactly
976
+ * one fully delivered, readable detail-target item ID.
977
+ * @returns Separate lists of newly accepted and already-counted item IDs for that event.
978
+ * @throws {MobileServerFailureError} On invalid parameters, an unregistered or rebound event
979
+ * (`SOCIAL_FEED_VIEW_EVENT_REBOUND`), session mismatch or expiry, or an ineligible item.
980
+ * Acquire a new session after expiry, re-register the same event via getFeedItem, then retry.
981
+ */
982
+ async recordFeedViews(
983
+ params: MobileRecordFeedViewsParams,
984
+ ): Promise<MobileSocialFeedViewsResult> {
985
+ const body: MobileServerPublicExecuteRequest<'record_feed_views'> = {
986
+ type: 'record_feed_views',
987
+ session_id: params.sessionId,
988
+ viewer_token: params.viewerToken,
989
+ view_event_id: params.viewEventId,
990
+ item_ids: [params.itemId],
991
+ };
992
+ return mapMobileSocialFeedViewsResult(await this.publicExecute(body));
993
+ }
994
+
995
+ /**
996
+ * Registers, renews, or leaves a page lease without signing or authenticating the displayed account.
997
+ * Omitting watcherSubaccount preserves its value; null clears it. This operation does not record item views.
998
+ * @param params - Authorized position, original session and viewer token, page-scoped viewSessionId,
999
+ * lease state, and optional self-reported display account. Retain viewSessionId for the lifetime of the page.
1000
+ * @returns Visitor count, public previews, recommended heartbeat interval, and remaining lease lifetime.
1001
+ * @throws {MobileServerFailureError} On invalid parameters, session mismatch or expiry, or an inaccessible
1002
+ * position. Rejected requests leave leases unchanged; acquire a new reading session after expiry.
1003
+ */
1004
+ async setPositionPresence(
1005
+ params: MobilePositionPresenceParams,
1006
+ ): Promise<MobileSocialFeedPresence> {
1007
+ const body: MobileServerPublicExecuteRequest<'position_presence'> = {
1008
+ type: 'position_presence',
1009
+ position_id: params.positionId,
1010
+ session_id: params.sessionId,
1011
+ view_session_id: params.viewSessionId,
1012
+ state: params.state,
1013
+ viewer_token: params.viewerToken,
1014
+ ...(params.watcherSubaccount === undefined
1015
+ ? {}
1016
+ : {
1017
+ watcher_subaccount:
1018
+ params.watcherSubaccount === null
1019
+ ? null
1020
+ : subaccountToHex(params.watcherSubaccount),
1021
+ }),
1022
+ };
1023
+ return mapMobileSocialFeedPresence(await this.publicExecute(body));
1024
+ }
1025
+
564
1026
  /*
565
1027
  Signed executes
566
1028
  */
@@ -661,11 +1123,13 @@ export class MobileClient {
661
1123
 
662
1124
  /**
663
1125
  * Registers an Expo push token for the wallet, transferring active ownership of the token if another
664
- * wallet had registered it. Idempotent per `(wallet, token)`.
1126
+ * wallet had registered it. Each registration advances its generation and cancels old pending deliveries.
1127
+ * This legacy method replaces capabilities with v1; use registerExpoTokenV2 consistently after upgrading.
665
1128
  *
666
1129
  * @throws {MobileServerFailureError} With error code `INVALID_EXPO_TOKEN` if the token is not a valid Expo
667
1130
  * push token, or `INVALID_DEVICE_METADATA` if `locale` (max 35 chars) or `appVersion` (max 64 chars) is
668
1131
  * too long.
1132
+ * @deprecated Use {@link registerExpoTokenV2} instead.
669
1133
  */
670
1134
  async registerExpoToken(
671
1135
  params: MobileRegisterExpoTokenParams,
@@ -683,6 +1147,70 @@ export class MobileClient {
683
1147
  return this.execute(signedRequest);
684
1148
  }
685
1149
 
1150
+ /**
1151
+ * Registers a device with its actual v2 capabilities; do not use repeated registration as a heartbeat.
1152
+ * @param params - Wallet authentication, Expo token, metadata, and supported notification types/routes.
1153
+ * @returns Success only; query registration separately for its new generation.
1154
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1155
+ * @throws {MobileServerFailureError} On `INVALID_EXPO_TOKEN`, `INVALID_DEVICE_METADATA`,
1156
+ * `NOTIFICATION_DEVICE_LIMIT` when the wallet already has 32 active devices, or authentication errors.
1157
+ */
1158
+ async registerExpoTokenV2(
1159
+ params: MobileRegisterExpoTokenV2Params,
1160
+ ): Promise<MobileServerSuccessResponse> {
1161
+ const request = await this.getSignedRequest(
1162
+ 'register_expo_token_v2',
1163
+ params,
1164
+ {
1165
+ expo_token: params.expoToken,
1166
+ platform: params.platform,
1167
+ locale: params.locale ?? null,
1168
+ app_version: params.appVersion ?? null,
1169
+ capabilities: mapMobileNotificationCapabilitiesToServer(
1170
+ params.capabilities,
1171
+ ),
1172
+ },
1173
+ );
1174
+ return this.execute(request);
1175
+ }
1176
+
1177
+ /**
1178
+ * Applies exactly one bell, market, or one-time favorites-import operation.
1179
+ * @param params - Wallet authentication and subscription update with the latest subscription revision.
1180
+ * @returns Success only; re-query subscriptions for the new revision even after a repeated ON/OFF.
1181
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1182
+ * @throws {MobileServerFailureError} On `NOTIFICATION_REVISION_CONFLICT`, `INVALID_NOTIFICATION_REQUEST`, or
1183
+ * `INVALID_IDENTITY_TARGET`.
1184
+ */
1185
+ async updateNotificationSubscriptions(
1186
+ params: MobileUpdateNotificationSubscriptionsParams,
1187
+ ): Promise<MobileServerSuccessResponse> {
1188
+ const request = await this.getSignedRequest(
1189
+ 'update_notification_subscriptions',
1190
+ params,
1191
+ mapMobileNotificationSubscriptionsUpdateToServer(params.update),
1192
+ );
1193
+ return this.execute(request);
1194
+ }
1195
+
1196
+ /**
1197
+ * Atomically records 1-50 analytics events after the user has consented to analytics.
1198
+ * @param params - Wallet authentication and events with stable UUIDs and actual millisecond timestamps.
1199
+ * @returns Success only; reuse event IDs on retries. Notification clicks do not mark an inbox item as read.
1200
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1201
+ * @throws {MobileServerFailureError} If any event, timestamp, batch size, or notification ownership is invalid.
1202
+ */
1203
+ async recordProductEvents(
1204
+ params: MobileRecordProductEventsParams,
1205
+ ): Promise<MobileServerSuccessResponse> {
1206
+ const request = await this.getSignedRequest(
1207
+ 'record_product_events',
1208
+ params,
1209
+ { events: params.events.map(mapMobileProductEventToServer) },
1210
+ );
1211
+ return this.execute(request);
1212
+ }
1213
+
686
1214
  /**
687
1215
  * Sets whether the signing subaccount follows a Profile. Both directions are idempotent: following again
688
1216
  * keeps the original relationship creation time, so it does not move the account in recency order, and
@@ -740,6 +1268,170 @@ export class MobileClient {
740
1268
  return mapMobileFollowBatchResult(data);
741
1269
  }
742
1270
 
1271
+ /**
1272
+ * Publishes text, a drawing, or both atomically using the signed author identity.
1273
+ * For an idempotent retry, reuse clientRequestId and the exact original content with a valid signature.
1274
+ * The SDK does not trim text or reformat the signed drawing JSON.
1275
+ * @param params - Author subaccount and signing options, request UUID, owned position, original text and
1276
+ * mentions, plus an optional trusted action and original drawing JSON.
1277
+ * @returns The published item, including authoritative interaction state and any drawing or comment preview.
1278
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1279
+ * @throws {MobileServerFailureError} On authentication, ownership, eligibility, content, mention, or drawing
1280
+ * errors, or `SOCIAL_FEED_REQUEST_CONFLICT` when a request UUID is reused with different content. Do not
1281
+ * change an earlier request to retry it; use a new UUID for a genuinely new publication.
1282
+ * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
1283
+ */
1284
+ async createFeedPost(
1285
+ params: MobileCreateFeedPostParams,
1286
+ ): Promise<MobileSocialFeedItem> {
1287
+ const request = await this.getSignedRequest('create_feed_post', params, {
1288
+ client_request_id: params.clientRequestId,
1289
+ position_id: params.positionId,
1290
+ action_id: params.actionId,
1291
+ text: params.text,
1292
+ mentions: params.mentions.map(mapMobileSocialFeedMentionToServer),
1293
+ drawing_data_json: params.drawingDataJson,
1294
+ image_ids: params.imageIds,
1295
+ });
1296
+ return mapMobileSocialFeedItem((await this.execute(request)).item);
1297
+ }
1298
+
1299
+ /**
1300
+ * Uploads one static JPEG/PNG for a later {@link createFeedPost} via multipart execute.
1301
+ * The whole HTTP request must stay within 2 MiB including signature overhead; upload one file per call
1302
+ * and bind up to nine ready IDs at publication. There is no complete/PUT step — success means ready.
1303
+ * @param params - Author subaccount and signing options, plus the original file bytes.
1304
+ * @returns Ready image metadata, including original and thumbnail paths.
1305
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1306
+ * @throws {RangeError} If the complete multipart request exceeds {@link MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES}.
1307
+ * @throws {MobileServerFailureError} On authentication, format/size/hash errors (`INVALID_SOCIAL_FEED_IMAGE`),
1308
+ * or when publishing is disabled (`SERVICE_UNAVAILABLE`), or image storage is unavailable
1309
+ * (`SOCIAL_FEED_DATA_UNAVAILABLE`, 6320, HTTP 503).
1310
+ */
1311
+ async createFeedPostImageUpload(
1312
+ params: MobileCreateFeedImageUploadParams,
1313
+ ): Promise<MobileSocialFeedImage> {
1314
+ return this.createFeedImageUpload('create_feed_post_image_uploads', params);
1315
+ }
1316
+
1317
+ /**
1318
+ * Uploads one static JPEG/PNG for a later {@link createFeedComment} via multipart execute.
1319
+ * Same size and readiness rules as {@link createFeedPostImageUpload}; comment text remains required.
1320
+ * @param params - Author subaccount and signing options, plus the original file bytes.
1321
+ * @returns Ready image metadata, including original and thumbnail paths.
1322
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1323
+ * @throws {RangeError} If the complete multipart request exceeds {@link MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES}.
1324
+ * @throws {MobileServerFailureError} On authentication, format/size/hash errors (`INVALID_SOCIAL_FEED_IMAGE`),
1325
+ * or when comments are disabled (`SERVICE_UNAVAILABLE`), or image storage is unavailable
1326
+ * (`SOCIAL_FEED_DATA_UNAVAILABLE`, 6320, HTTP 503).
1327
+ */
1328
+ async createFeedCommentImageUpload(
1329
+ params: MobileCreateFeedImageUploadParams,
1330
+ ): Promise<MobileSocialFeedImage> {
1331
+ return this.createFeedImageUpload(
1332
+ 'create_feed_comment_image_uploads',
1333
+ params,
1334
+ );
1335
+ }
1336
+
1337
+ /**
1338
+ * First attaches a drawing to an owned post or trade card while the author still holds its position.
1339
+ * The original JSON is signed unchanged; false and zero are valid drawing documents.
1340
+ * For an exact retry after a timeout, generate a nonce up front with {@link getMobileNonce} and reuse
1341
+ * that nonce and the original JSON before its receive deadline. A fresh nonce is not an exact replay.
1342
+ * If a retry returns `SOCIAL_FEED_DRAWING_EXISTS`, use {@link getFeedChartDrawing} to confirm that the
1343
+ * stored data matches the intended drawing before treating the original create as successful.
1344
+ * @param params - Author subaccount and signing options, parent item, and complete original drawing JSON.
1345
+ * @returns The parent ID and updated version together with the stored drawing.
1346
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1347
+ * @throws {MobileServerFailureError} On authentication, ownership, eligibility, or invalid/oversized drawing
1348
+ * errors, an unavailable parent, or `SOCIAL_FEED_DRAWING_EXISTS` for a conflicting existing drawing.
1349
+ * Read the existing drawing and use updateFeedChartDrawing when replacement is intended.
1350
+ */
1351
+ async createFeedChartDrawing(
1352
+ params: MobileFeedChartDrawingParams,
1353
+ ): Promise<MobileSocialFeedDrawingMutationResult> {
1354
+ const request = await this.getSignedRequest(
1355
+ 'create_feed_chart_drawing',
1356
+ params,
1357
+ { item_id: params.itemId, data_json: params.dataJson },
1358
+ );
1359
+ return mapMobileSocialFeedDrawingMutationResult(
1360
+ await this.execute(request),
1361
+ );
1362
+ }
1363
+
1364
+ /**
1365
+ * Replaces an existing drawing, including after the associated position has closed.
1366
+ * Serialize writes per item and preserve the original JSON text when retrying.
1367
+ * @param params - Author subaccount and signing options, parent item, and complete replacement JSON.
1368
+ * @returns The parent ID and updated version together with the stored replacement drawing.
1369
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1370
+ * @throws {MobileServerFailureError} On authentication, ownership, or invalid/oversized drawing errors, an
1371
+ * unavailable parent or drawing, or `STALE_SOCIAL_FEED_DRAWING_UPDATE`. Re-read the drawing before retrying
1372
+ * a stale or conflicting update instead of blindly replacing newer content.
1373
+ */
1374
+ async updateFeedChartDrawing(
1375
+ params: MobileFeedChartDrawingParams,
1376
+ ): Promise<MobileSocialFeedDrawingMutationResult> {
1377
+ const request = await this.getSignedRequest(
1378
+ 'update_feed_chart_drawing',
1379
+ params,
1380
+ { item_id: params.itemId, data_json: params.dataJson },
1381
+ );
1382
+ return mapMobileSocialFeedDrawingMutationResult(
1383
+ await this.execute(request),
1384
+ );
1385
+ }
1386
+
1387
+ /**
1388
+ * Publishes a comment or reply atomically; an invalid position attachment rejects the entire request.
1389
+ * For an idempotent retry, reuse clientRequestId and the unmodified text, mentions, and attachment.
1390
+ * @param params - Author subaccount and signing options, request UUID, root item, original nonblank text
1391
+ * and mentions, plus an optional reply target in the same thread and currently owned position attachment.
1392
+ * @returns The created reply and authoritative root comment count; this write does not create a reading session.
1393
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1394
+ * @throws {MobileServerFailureError} On authentication, inaccessible content, invalid text/mentions/reply
1395
+ * relationships, an ineligible attachment, or `SOCIAL_FEED_REQUEST_CONFLICT`. Correct invalid input before
1396
+ * a new submission, and never reuse an existing request UUID with different content.
1397
+ */
1398
+ async createFeedComment(
1399
+ params: MobileCreateFeedCommentParams,
1400
+ ): Promise<MobileSocialFeedCommentResult> {
1401
+ const request = await this.getSignedRequest('create_feed_comment', params, {
1402
+ client_request_id: params.clientRequestId,
1403
+ root_item_id: params.rootItemId,
1404
+ reply_to_item_id: params.replyToItemId,
1405
+ text: params.text,
1406
+ mentions: params.mentions.map(mapMobileSocialFeedMentionToServer),
1407
+ attached_position_id: params.attachedPositionId,
1408
+ image_ids: params.imageIds,
1409
+ });
1410
+ return mapMobileSocialFeedCommentResult(await this.execute(request));
1411
+ }
1412
+
1413
+ /**
1414
+ * Sets or clears a signed user's like without requiring an open position.
1415
+ * Serialize mutations per item and author. Retrying the same isLiked state with a fresh nonce is safe
1416
+ * when no newer change intervenes; an unchanged state does not increment the count or version again.
1417
+ * Pass the original nonce on a retry before its deadline to avoid overwriting a newer change from
1418
+ * another device. Re-read the current state if that retry conflicts.
1419
+ * @param params - Acting subaccount and signing options, interactive item, and desired like state.
1420
+ * @returns The applied like state, authoritative count, and item version after the mutation.
1421
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
1422
+ * @throws {MobileServerFailureError} On authentication errors, inaccessible or non-interactive content,
1423
+ * or `STALE_SOCIAL_FEED_LIKE_UPDATE`. Re-read the current state before submitting a new mutation after a conflict.
1424
+ */
1425
+ async setFeedLike(
1426
+ params: MobileSetFeedLikeParams,
1427
+ ): Promise<MobileSocialFeedLikeResult> {
1428
+ const request = await this.getSignedRequest('set_feed_like', params, {
1429
+ item_id: params.itemId,
1430
+ is_liked: params.isLiked,
1431
+ });
1432
+ return mapMobileSocialFeedLikeResult(await this.execute(request));
1433
+ }
1434
+
743
1435
  /*
744
1436
  Base Fns
745
1437
  */
@@ -783,9 +1475,30 @@ export class MobileClient {
783
1475
  return response.data as MobileServerPublicQuerySuccessResponse<T>;
784
1476
  }
785
1477
 
786
- protected async publicExecute(
787
- body: MobileServerPublicExecuteRequest,
788
- ): Promise<MobileServerSuccessResponse> {
1478
+ protected async publicGetBytes(
1479
+ url: string,
1480
+ headers: Record<string, string>,
1481
+ ): Promise<Uint8Array> {
1482
+ const response = await this.axiosInstance.get<ArrayBuffer>(url, {
1483
+ responseType: 'arraybuffer',
1484
+ headers,
1485
+ });
1486
+ if (response.status < 200 || response.status >= 300) {
1487
+ const responseText = bytesToString(new Uint8Array(response.data));
1488
+ let errorData: unknown;
1489
+ try {
1490
+ errorData = JSON.parse(responseText);
1491
+ } catch {
1492
+ errorData = responseText;
1493
+ }
1494
+ this.checkResponseStatus({ ...response, data: errorData });
1495
+ }
1496
+ return new Uint8Array(response.data);
1497
+ }
1498
+
1499
+ protected async publicExecute<T extends MobileServerPublicExecuteRequestType>(
1500
+ body: { type: T } & MobileServerPublicExecuteRequestByType[T],
1501
+ ): Promise<MobileServerPublicExecuteSuccessResponse<T>> {
789
1502
  const response = await this.axiosInstance.post<MobileServerExecuteResult>(
790
1503
  `${this.opts.url}/public_execute`,
791
1504
  body,
@@ -795,17 +1508,46 @@ export class MobileClient {
795
1508
  this.checkServerStatus(response);
796
1509
 
797
1510
  // checkServerStatus catches the failure result and throws the error, so the cast to the success response is acceptable here
798
- return response.data as MobileServerSuccessResponse;
1511
+ return response.data as MobileServerPublicExecuteSuccessResponse<T>;
1512
+ }
1513
+
1514
+ /**
1515
+ * Sends an authenticated read through the signed query route.
1516
+ * @param body - Canonical inner payload with its signature, sender, and nonce.
1517
+ * @returns The successful query envelope and its type-specific payload.
1518
+ * @throws {MobileServerFailureError} For a structured service failure, including non-2xx responses.
1519
+ */
1520
+ protected async query<T extends MobileServerSignedQueryRequestType>(
1521
+ body: MobileSignedRequest & { type: T },
1522
+ ): Promise<MobileServerSignedQuerySuccessResponse<T>> {
1523
+ const response = await this.axiosInstance.post<unknown>(
1524
+ `${this.opts.url}/query`,
1525
+ body,
1526
+ );
1527
+ this.checkResponseStatus(response);
1528
+ this.checkServerStatus(response);
1529
+ return response.data as MobileServerSignedQuerySuccessResponse<T>;
799
1530
  }
800
1531
 
801
1532
  // `T` is inferred from the body's `type` rather than declared by the caller, for the same reason
802
1533
  // `publicQuery` spells its body out as an intersection: an indexed access is not an inference site.
803
1534
  protected async execute<T extends MobileServerExecuteRequestType>(
804
1535
  body: MobileSignedRequest & { type: T },
1536
+ fileBytes?: Uint8Array,
805
1537
  ): Promise<MobileServerExecuteSuccessResponse<T>> {
1538
+ const multipart =
1539
+ fileBytes == null
1540
+ ? undefined
1541
+ : buildMobileFeedImageMultipart(JSON.stringify(body), fileBytes);
1542
+ if (multipart) {
1543
+ this.checkFeedImageRequestSize(multipart.body.byteLength);
1544
+ }
806
1545
  const response = await this.axiosInstance.post<MobileServerExecuteResult>(
807
1546
  `${this.opts.url}/execute`,
808
- body,
1547
+ multipart?.body ?? body,
1548
+ multipart
1549
+ ? { headers: { 'Content-Type': multipart.contentType } }
1550
+ : undefined,
809
1551
  );
810
1552
 
811
1553
  this.checkResponseStatus(response);
@@ -815,6 +1557,46 @@ export class MobileClient {
815
1557
  return response.data as MobileServerExecuteSuccessResponse<T>;
816
1558
  }
817
1559
 
1560
+ private async createFeedImageUpload(
1561
+ type:
1562
+ | 'create_feed_post_image_uploads'
1563
+ | 'create_feed_comment_image_uploads',
1564
+ params: MobileCreateFeedImageUploadParams,
1565
+ ): Promise<MobileSocialFeedImage> {
1566
+ const nonce = params.nonce ?? getMobileNonce();
1567
+ // Match the signed body's field lengths so oversized requests fail before prompting the wallet.
1568
+ const sizePayload = {
1569
+ type,
1570
+ content_hash: zeroHash,
1571
+ signature: `0x${'00'.repeat(65)}`,
1572
+ sender: subaccountToHex(params),
1573
+ nonce: nonce.toString(),
1574
+ };
1575
+ const overhead = buildMobileFeedImageMultipart(
1576
+ JSON.stringify(sizePayload),
1577
+ new Uint8Array(),
1578
+ ).body.byteLength;
1579
+ this.checkFeedImageRequestSize(overhead + params.fileBytes.byteLength);
1580
+ const contentHash = keccak256(params.fileBytes);
1581
+ const request = await this.getSignedRequest(
1582
+ type,
1583
+ { ...params, nonce },
1584
+ {
1585
+ content_hash: contentHash,
1586
+ },
1587
+ );
1588
+ const data = await this.execute(request, params.fileBytes);
1589
+ return mapMobileSocialFeedImage(data.image);
1590
+ }
1591
+
1592
+ private checkFeedImageRequestSize(byteLength: number): void {
1593
+ if (byteLength > MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES) {
1594
+ throw new RangeError(
1595
+ `Feed image upload request exceeds ${MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES} bytes (2 MiB).`,
1596
+ );
1597
+ }
1598
+ }
1599
+
818
1600
  /**
819
1601
  * Validates the HTTP status before interpreting the body. Unlike the engine, the mobile backend returns
820
1602
  * failure envelopes with non-2xx statuses (e.g. 404 for `PROFILE_NOT_FOUND`), so a non-2xx response with a