@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
@@ -1,24 +1,64 @@
1
1
  import { Hex } from 'viem';
2
2
  import { MobileServerSuccessResponse } from './serverBaseTypes';
3
3
  import {
4
- MobileNotificationPlatform,
5
4
  MobileServerAvatarPreset,
6
5
  MobileServerFeedTrade,
7
6
  MobileServerFollowListAccount,
7
+ MobileServerNotificationCapabilities,
8
+ MobileServerNotificationDeviceMetadata,
9
+ MobileServerNotificationInboxItem,
8
10
  MobileServerNotificationPreferences,
11
+ MobileServerNotificationSettings,
9
12
  MobileServerProfile,
13
+ MobileServerSocialFeedActionCandidate,
14
+ MobileServerSocialFeedActionMarker,
15
+ MobileServerSocialFeedAuthor,
16
+ MobileServerSocialFeedCandle,
10
17
  MobileServerSocialFeedCohort,
18
+ MobileServerSocialFeedDrawing,
19
+ MobileServerSocialFeedEstimatedLiquidationLine,
20
+ MobileServerSocialFeedHistorySummary,
11
21
  MobileServerSocialFeedItem,
12
22
  MobileServerSocialFeedItemPatch,
23
+ MobileServerSocialFeedMarket,
24
+ MobileServerSocialFeedPositionHistoryCard,
13
25
  MobileServerSocialFeedPositionPatch,
26
+ MobileServerSocialFeedPublishablePosition,
14
27
  MobileServerSocialFeedReadSession,
28
+ MobileServerSocialFeedReply,
29
+ MobileServerSocialFeedTimelineEntry,
30
+ MobileServerSocialFeedTradingContext,
31
+ MobileSocialFeedActionResolution,
32
+ MobileSocialFeedChartDataQuality,
33
+ MobileSocialFeedHistoryQuality,
34
+ MobileSocialFeedPositionResolution,
35
+ MobileSocialFeedPositionResolutionReason,
15
36
  MobileSocialFeedUnavailableTarget,
16
37
  } from './serverModelTypes';
17
38
  import {
18
39
  MobileServerPublicQueryRequestByType,
19
40
  MobileServerPublicQueryRequestType,
41
+ MobileServerSignedQueryRequestType,
20
42
  } from './serverRequestTypes';
21
43
 
44
+ /**
45
+ * Success payloads for each signed `query`, keyed by request `type`.
46
+ */
47
+ export interface MobileServerSignedQueryResponseByType {
48
+ /** Wallet subscriptions and the signing Identity's bells. */
49
+ notification_subscriptions: MobileServerNotificationSubscriptionsResponse;
50
+ /** Private notification page. */
51
+ notification_inbox_v2: MobileServerNotificationInboxV2Response;
52
+ }
53
+
54
+ /**
55
+ * Full success response for a signed `query`, with its payload inlined alongside `status`.
56
+ */
57
+ export type MobileServerSignedQuerySuccessResponse<
58
+ T extends MobileServerSignedQueryRequestType =
59
+ MobileServerSignedQueryRequestType,
60
+ > = MobileServerSuccessResponse & MobileServerSignedQueryResponseByType[T];
61
+
22
62
  /**
23
63
  * Unsigned `public_query` request body: a `type` discriminant flattened with its params.
24
64
  */
@@ -147,15 +187,58 @@ export interface MobileServerNotificationPreferencesResponse {
147
187
  preferences: MobileServerNotificationPreferences;
148
188
  }
149
189
 
190
+ /**
191
+ * Payload of the `notification_registration_v2` public query, including legacy registrations.
192
+ */
193
+ export interface MobileServerNotificationRegistrationV2Response {
194
+ /** Opaque decimal string; do not convert to a JavaScript number. */
195
+ registration_generation: string;
196
+ /** Persisted capabilities of the most recent registration; legacy type/route arrays are empty. */
197
+ capabilities: MobileServerNotificationCapabilities;
198
+ }
199
+
200
+ /**
201
+ * Full settings document returned by both `notification_settings_v2` and `update_notification_settings_v2`.
202
+ */
203
+ export interface MobileServerNotificationSettingsV2Response {
204
+ /** Settings schema version. */
205
+ schema_version: 2;
206
+ /** Settings revision, independent of the subscription revision. */
207
+ revision: number;
208
+ /** Full saved settings. */
209
+ settings: MobileServerNotificationSettings;
210
+ }
211
+
212
+ /**
213
+ * Payload of the `notification_subscriptions` signed query.
214
+ */
215
+ export interface MobileServerNotificationSubscriptionsResponse {
216
+ /** Wallet-level subscription revision; read again after every mutation. */
217
+ revision: number;
218
+ /** Whether the one-time local favorites import has completed. */
219
+ favorites_imported: boolean;
220
+ /** Subscribed market IDs in ascending order. */
221
+ market_ids: number[];
222
+ /** Followed subaccounts with bells enabled for the signing Identity. */
223
+ trader_bells: Hex[];
224
+ }
225
+
226
+ /**
227
+ * Payload of the `notification_inbox_v2` signed query, ordered newest first.
228
+ */
229
+ export interface MobileServerNotificationInboxV2Response {
230
+ /** Accepted intents owned by the signing wallet. */
231
+ notifications: MobileServerNotificationInboxItem[];
232
+ /** Pass unchanged to the next request, or null when pagination is complete. */
233
+ next_cursor: string | null;
234
+ }
235
+
150
236
  /**
151
237
  * Payload of the `registered_wallet` public query success response. Inlined into the envelope rather than
152
238
  * nested under a key, matching the backend's `RegisteredWalletResponse`.
153
239
  */
154
- export interface MobileServerRegisteredWalletResponse {
240
+ export interface MobileServerRegisteredWalletResponse extends MobileServerNotificationDeviceMetadata {
155
241
  wallet: Hex;
156
- platform: MobileNotificationPlatform;
157
- locale: string | null;
158
- app_version: string | null;
159
242
  token_fingerprint_prefix: string;
160
243
  last_seen_at: number;
161
244
  }
@@ -167,6 +250,26 @@ export interface MobileServerRegisteredWalletResponse {
167
250
  * by {@link MobileServerPublicQuerySuccessResponse}.
168
251
  */
169
252
  export interface MobileServerPublicQueryResponseByType {
253
+ /** Latest saved device generation and v1/v2 capabilities. */
254
+ notification_registration_v2: MobileServerNotificationRegistrationV2Response;
255
+ /** Full settings document with its revision. */
256
+ notification_settings_v2: MobileServerNotificationSettingsV2Response;
257
+ /** Open position candidates. */
258
+ self_feed_positions: MobileServerSocialFeedPositionsResponse;
259
+ /** Position command resolution. */
260
+ resolve_feed_position: MobileServerSocialFeedPositionResolutionResponse;
261
+ /** Trusted order action resolution. */
262
+ resolve_feed_action: MobileServerSocialFeedActionResolutionResponse;
263
+ /** Parent drawing and version. */
264
+ feed_chart_drawing: MobileServerSocialFeedDrawingResponse;
265
+ /** Comment thread page. */
266
+ feed_comments: MobileServerSocialFeedCommentsResponse;
267
+ /** Full lifecycle history. */
268
+ position_history: MobileServerSocialFeedPositionHistoryResponse;
269
+ /** Candle page and markers. */
270
+ position_chart: MobileServerSocialFeedPositionChartResponse;
271
+ /** Read-only watcher observation. */
272
+ position_watchers: MobileServerSocialFeedWatchersResponse;
170
273
  /** Preset IDs and public image URLs in display order. */
171
274
  avatar_presets: MobileServerAvatarPresetsResponse;
172
275
  /** For You recommendations. */
@@ -204,3 +307,107 @@ export type MobileServerPublicQuerySuccessResponse<
204
307
  T extends MobileServerPublicQueryRequestType =
205
308
  MobileServerPublicQueryRequestType,
206
309
  > = MobileServerSuccessResponse & MobileServerPublicQueryResponseByType[T];
310
+
311
+ /** Selected account's current candidates. */
312
+ export interface MobileServerSocialFeedPositionsResponse {
313
+ /** Position eligibility hints. */
314
+ positions: MobileServerSocialFeedPublishablePosition[];
315
+ /** Next bound cursor, or null. */
316
+ next_cursor: string | null;
317
+ /** Observation time. */
318
+ as_of_ms: number;
319
+ }
320
+
321
+ /** Slash-command resolution, including normal empty outcomes. */
322
+ export interface MobileServerSocialFeedPositionResolutionResponse {
323
+ /** Resolution status. */
324
+ resolution: MobileSocialFeedPositionResolution;
325
+ /** Resolved market, or null. */
326
+ product: MobileServerSocialFeedMarket | null;
327
+ /** Current candidates. */
328
+ candidates: MobileServerSocialFeedPublishablePosition[];
329
+ /** Explanation for empty candidates. */
330
+ reason: MobileSocialFeedPositionResolutionReason | null;
331
+ }
332
+
333
+ /** Authoritative order segments, not an inferred latest trade. */
334
+ export interface MobileServerSocialFeedActionResolutionResponse {
335
+ /** Requested order. */
336
+ order_digest: Hex;
337
+ /** Pending until all confirmed segments are projected. */
338
+ resolution: MobileSocialFeedActionResolution;
339
+ /** Trusted actions, empty when pending. */
340
+ actions: MobileServerSocialFeedActionCandidate[];
341
+ /** Observation time. */
342
+ as_of_ms: number;
343
+ }
344
+
345
+ /** Drawing read result; a readable parent without a drawing succeeds with null. */
346
+ export interface MobileServerSocialFeedDrawingResponse {
347
+ /** Parent UUID. */
348
+ item_id: string;
349
+ /** Display version. */
350
+ item_version: string;
351
+ /** Parsed drawing, or null. */
352
+ drawing: MobileServerSocialFeedDrawing | null;
353
+ }
354
+
355
+ /** Comment thread, including bidirectional pagination around an optional anchor. */
356
+ export interface MobileServerSocialFeedCommentsResponse {
357
+ /** Readable comments. */
358
+ comments: MobileServerSocialFeedReply[];
359
+ /** Total readable count. */
360
+ total_count: number;
361
+ /** Forward cursor. */
362
+ next_cursor: string | null;
363
+ /** Backward cursor. */
364
+ previous_cursor: string | null;
365
+ /** Requested anchor, or null. */
366
+ anchor_reply_id: string | null;
367
+ /** Original or new session. */
368
+ read_session: MobileServerSocialFeedReadSession;
369
+ }
370
+
371
+ /** Full position history with additional metrics and trusted trading hints. */
372
+ export interface MobileServerSocialFeedPositionHistoryResponse {
373
+ /** Current or frozen position and history metrics. */
374
+ position: MobileServerSocialFeedPositionHistoryCard;
375
+ /** Counts across the authorized history. */
376
+ summary: MobileServerSocialFeedHistorySummary;
377
+ /** Ordered action and take entries. */
378
+ timeline: MobileServerSocialFeedTimelineEntry[];
379
+ /** Next history cursor. */
380
+ next_cursor: string | null;
381
+ /** History completeness. */
382
+ history_quality: MobileSocialFeedHistoryQuality;
383
+ /** Position-mode session. */
384
+ read_session: MobileServerSocialFeedReadSession;
385
+ /** Viewing-account state, not authentication. */
386
+ trading_context: MobileServerSocialFeedTradingContext;
387
+ }
388
+
389
+ /** Candles and actions, with separate estimated risk-price line. */
390
+ export interface MobileServerSocialFeedPositionChartResponse {
391
+ /** Descending candle page. */
392
+ candles: MobileServerSocialFeedCandle[];
393
+ /** Action markers with explicit price bases. */
394
+ action_markers: MobileServerSocialFeedActionMarker[];
395
+ /** Estimated line, if applicable and available. */
396
+ estimated_liquidation_line: MobileServerSocialFeedEstimatedLiquidationLine | null;
397
+ /** Exclusive next-page bound. */
398
+ next_before_ms: number | null;
399
+ /** Observation time. */
400
+ as_of_ms: number;
401
+ /** Overall source quality. */
402
+ data_quality: MobileSocialFeedChartDataQuality;
403
+ }
404
+
405
+ /** Read-only watcher observation; account previews are self-reported. */
406
+ export interface MobileServerSocialFeedWatchersResponse {
407
+ /** Distinct active browsing credentials. */
408
+ watcher_count: number;
409
+ /** Deduplicated public account previews. */
410
+ watcher_preview: MobileServerSocialFeedAuthor[];
411
+ /** Observation time. */
412
+ as_of_ms: number;
413
+ }
@@ -1,10 +1,73 @@
1
1
  import { Hex } from 'viem';
2
2
  import { MobileSignedInner } from '../signing/types';
3
3
  import {
4
+ MobileNotificationRouteName,
5
+ MobileNotificationTypeId,
6
+ MobileServerNotificationDeviceMetadata,
4
7
  MobileServerNotificationPreferences,
8
+ MobileServerNotificationSettings,
9
+ MobileServerSocialFeedChartRange,
10
+ MobileSocialFeedChartInterval,
5
11
  MobileSocialFeedMarketCategory,
12
+ MobileSocialFeedPresenceState,
6
13
  MobileSocialFeedType,
7
14
  } from './serverModelTypes';
15
+ import type { MobileServerSignedQueryResponseByType } from './serverQueryTypes';
16
+
17
+ /**
18
+ * Common wire-format credential for token-authenticated notification requests.
19
+ * Unregistration also accepts an inactive or unknown well-formed token.
20
+ */
21
+ export interface MobileServerWithExpoTokenParams {
22
+ /** Expo push token; never expose it to another user. */
23
+ expo_token: string;
24
+ }
25
+
26
+ /**
27
+ * Registration fields shared by v1 and v2 signed inner payloads.
28
+ * Nullable metadata keys remain present when signing so the MessagePack hash matches the backend.
29
+ */
30
+ export interface MobileServerRegisterExpoTokenParams
31
+ extends
32
+ MobileServerWithExpoTokenParams,
33
+ MobileServerNotificationDeviceMetadata {}
34
+
35
+ /** Registration request with a v2-only capability declaration. */
36
+ export interface MobileServerRegisterExpoTokenV2Params extends MobileServerRegisterExpoTokenParams {
37
+ /** Actual notification features supported by the device. */
38
+ capabilities: {
39
+ /** Registration accepts only the v2 protocol. */
40
+ payload_versions: [2];
41
+ /** Supported notification types. */
42
+ type_ids: MobileNotificationTypeId[];
43
+ /** Supported navigation destinations. */
44
+ routes: MobileNotificationRouteName[];
45
+ };
46
+ }
47
+
48
+ /**
49
+ * One subscription operation; exactly one operation is non-null and unused operations must be null.
50
+ */
51
+ export interface MobileServerNotificationSubscriptionsUpdate {
52
+ /** Latest subscription revision, not the settings revision. */
53
+ expected_revision: number;
54
+ /** Set one bell; enabling requires an existing follow relationship. */
55
+ trader_bell: {
56
+ /** Target non-isolated subaccount belonging to another wallet. */
57
+ subaccount: Hex;
58
+ /** Desired bell state. */
59
+ enabled: boolean;
60
+ } | null;
61
+ /** Subscribe or unsubscribe one known market. */
62
+ market: {
63
+ /** Positive market product ID. */
64
+ product_id: number;
65
+ /** Desired subscription state. */
66
+ subscribed: boolean;
67
+ } | null;
68
+ /** One-time merge of up to 500 local market IDs; mutually exclusive with the other operations. */
69
+ import_markets: number[] | null;
70
+ }
8
71
 
9
72
  /**
10
73
  * Opt-in extras for a `profiles` query. Each one costs extra rate-limit weight per profile and adds fields
@@ -65,7 +128,7 @@ export interface MobileServerSocialFeedListParams {
65
128
  minimum_notional?: number;
66
129
  /** Page size, 1–50; defaults to 20. */
67
130
  limit?: number;
68
- /** Fixed 15-minute reading session; required with cursor. */
131
+ /** Original reading session; required with cursor. Legitimate requests renew its idle expiration. */
69
132
  session_id?: string;
70
133
  /** Opaque pagination cursor, distinct from update_cursor and watermark. */
71
134
  cursor?: string;
@@ -92,6 +155,88 @@ export interface MobileServerSocialFeedReadParams {
92
155
  * Params for each unsigned `public_query`, keyed by request `type`.
93
156
  */
94
157
  export interface MobileServerPublicQueryRequestByType {
158
+ /** Selected account's open position candidates. */
159
+ self_feed_positions: {
160
+ /** Full identity. */
161
+ view_as: Hex;
162
+ /** Market filter. */
163
+ product_id?: number;
164
+ /** Bound pagination cursor. */
165
+ cursor?: string;
166
+ /** Page size, 1-50. */
167
+ limit?: number;
168
+ };
169
+ /** Resolve a position command without signing. */
170
+ resolve_feed_position: {
171
+ /** Full identity. */
172
+ view_as: Hex;
173
+ /** Unmodified command text. */
174
+ input: string;
175
+ /** Optional market disambiguation. */
176
+ product_id?: number;
177
+ };
178
+ /** Resolve an order's complete trusted lifecycle segments. */
179
+ resolve_feed_action: {
180
+ /** Order-owning identity. */
181
+ view_as: Hex;
182
+ /** Trading order digest. */
183
+ order_digest: Hex;
184
+ };
185
+ /** Read a drawing within the parent item's visibility. */
186
+ feed_chart_drawing: MobileServerSocialFeedReadParams & {
187
+ /** Parent UUID. */
188
+ item_id: string;
189
+ /** Original session, paired with viewer_token. */
190
+ session_id?: string;
191
+ };
192
+ /** Read or navigate a comment thread. */
193
+ feed_comments: MobileServerSocialFeedReadParams & {
194
+ /** Root UUID. */
195
+ root_item_id: string;
196
+ /** Thread cursor. */
197
+ cursor?: string;
198
+ /** Page size, 1-50. */
199
+ limit?: number;
200
+ /** First-page anchor, mutually exclusive with cursor. */
201
+ anchor_reply_id?: string;
202
+ /** Original reading session. */
203
+ session_id?: string;
204
+ };
205
+ /** Full lifecycle history rather than published feed items alone. */
206
+ position_history: MobileServerSocialFeedReadParams & {
207
+ /** Lifecycle UUID. */
208
+ position_id: string;
209
+ /** Filter to published takes. */
210
+ takes_only?: boolean;
211
+ /** History cursor. */
212
+ cursor?: string;
213
+ /** Page size, 1-50. */
214
+ limit?: number;
215
+ /** Original position-mode session. */
216
+ session_id?: string;
217
+ };
218
+ /** Market candles and independently priced action markers. */
219
+ position_chart: MobileServerSocialFeedReadParams & {
220
+ /** Lifecycle UUID. */
221
+ position_id: string;
222
+ /** Original session, paired with viewer_token. */
223
+ session_id?: string;
224
+ /** Candle interval. */
225
+ interval: MobileSocialFeedChartInterval;
226
+ /** Half-open time interval. */
227
+ range: MobileServerSocialFeedChartRange;
228
+ /** Exclusive next-page bound. */
229
+ before_ms?: number;
230
+ /** Page size, 1-500. */
231
+ limit?: number;
232
+ };
233
+ /** Watcher query; does not register presence. */
234
+ position_watchers: {
235
+ /** Lifecycle UUID. */
236
+ position_id: string;
237
+ /** Relationship perspective only. */
238
+ view_as?: Hex;
239
+ };
95
240
  /** Ordered server-owned avatar catalogue. */
96
241
  avatar_presets: Record<never, never>;
97
242
  /** Public recommendations with optional relationship perspective. */
@@ -128,6 +273,8 @@ export interface MobileServerPublicQueryRequestByType {
128
273
  feed_item: MobileServerSocialFeedReadParams & {
129
274
  /** Target item UUID. */
130
275
  item_id: string;
276
+ /** Detail-visit event; omit for prefetch. Does not increment the count alone. */
277
+ view_event_id?: string;
131
278
  /** Preview size, 0-3. */
132
279
  comment_preview_limit?: number;
133
280
  /** Omit to create a new reading session. */
@@ -178,8 +325,12 @@ export interface MobileServerPublicQueryRequestByType {
178
325
  */
179
326
  cursor?: string;
180
327
  };
181
- notification_preferences: { expo_token: string };
182
- registered_wallet: { expo_token: string };
328
+ notification_preferences: MobileServerWithExpoTokenParams;
329
+ /** Persisted device generation and capabilities. */
330
+ notification_registration_v2: MobileServerWithExpoTokenParams;
331
+ /** Versioned notification settings. */
332
+ notification_settings_v2: MobileServerWithExpoTokenParams;
333
+ registered_wallet: MobileServerWithExpoTokenParams;
183
334
  }
184
335
 
185
336
  /**
@@ -189,12 +340,48 @@ export type MobileServerPublicQueryRequestType =
189
340
  keyof MobileServerPublicQueryRequestByType;
190
341
 
191
342
  /**
192
- * Params for each unsigned `public_execute`, keyed by request `type`. Possession of an active Expo push token
193
- * authorizes these notification-only mutations: the backend resolves the token's owning wallet and mutates
194
- * its state, so no signature, sender, or nonce is sent. Ordering is the backend's last-write-wins commit
195
- * order, so callers must serialize their own writes.
343
+ * Params for each unsigned `public_execute`, keyed by request `type`. No signature, sender, or nonce is sent.
344
+ * `record_feed_views` and `position_presence` are authorized by the original reading session (`session_id`)
345
+ * and browser credential (`viewer_token`), not an Expo push token.
346
+ * For `unregister_expo_token` and `update_preferences`, possession of an active Expo push token authorizes
347
+ * the notification mutation: the backend resolves the token's owning wallet and mutates its state. These
348
+ * notification writes use the backend's last-write-wins commit order, so callers must serialize them.
196
349
  */
197
350
  export interface MobileServerPublicExecuteRequestByType {
351
+ /** Full settings replacement with optimistic concurrency control. */
352
+ update_notification_settings_v2: MobileServerWithExpoTokenParams & {
353
+ /** Latest settings revision. */
354
+ expected_revision: number;
355
+ /** Complete settings document. */
356
+ settings: MobileServerNotificationSettings;
357
+ };
358
+
359
+ /** Explicit detail-visit report using the original browsing credential. */
360
+ record_feed_views: {
361
+ /** Original reading session. */
362
+ session_id: string;
363
+ /** Original credential. */
364
+ viewer_token: string;
365
+ /** Detail-visit event previously registered on feed_item. */
366
+ view_event_id: string;
367
+ /** Exactly one fully delivered detail-target item. */
368
+ item_ids: string[];
369
+ };
370
+ /** Per-page visitor lease; no wallet signature. */
371
+ position_presence: {
372
+ /** Lifecycle UUID. */
373
+ position_id: string;
374
+ /** Original reading session. */
375
+ session_id: string;
376
+ /** Page-scoped UUID. */
377
+ view_session_id: string;
378
+ /** Lease lifecycle state. */
379
+ state: MobileSocialFeedPresenceState;
380
+ /** Original browsing credential. */
381
+ viewer_token: string;
382
+ /** Omission preserves the display account; null clears it. */
383
+ watcher_subaccount?: Hex | null;
384
+ };
198
385
  unregister_expo_token: { expo_token: string };
199
386
  update_preferences: {
200
387
  expo_token: string;
@@ -209,20 +396,33 @@ export type MobileServerPublicExecuteRequestType =
209
396
  keyof MobileServerPublicExecuteRequestByType;
210
397
 
211
398
  /**
212
- * Discriminant `type` values for signed `execute` requests. Every signed route the SDK calls is a write, so
213
- * this is the full set of {@link MobileSignedInner} tags. Unlike the public queries these carry no separate
214
- * params map — a signed request body *is* its inner payload flattened with the envelope, so
399
+ * Discriminant `type` values for signed `execute` requests, excluding signed queries. Unlike the public
400
+ * queries these carry no separate params map — a signed request body is its inner payload flattened with the envelope, so
215
401
  * {@link MobileSignedInner} is the single source of truth for both the fields and their significant order.
216
402
  */
217
- export type MobileServerExecuteRequestType = MobileSignedInner['type'];
403
+ export type MobileServerExecuteRequestType = Exclude<
404
+ MobileSignedInner['type'],
405
+ MobileServerSignedQueryRequestType
406
+ >;
407
+
408
+ /**
409
+ * Discriminant `type` values for signed `query` requests, distinct from unsigned `public_query` requests.
410
+ */
411
+ export type MobileServerSignedQueryRequestType =
412
+ keyof MobileServerSignedQueryResponseByType;
218
413
 
219
414
  /**
220
415
  * Wire `request_type` the backend echoes on failure envelopes, prefixed by the route that produced it:
221
416
  * `public_query_*` for unsigned queries, `public_execute_*` for unsigned writes, and `execute_*` for signed
222
- * writes (e.g. `execute_set_username`). The prefix names the route, so it never carries the `mobile:` prefix
223
- * that the EIP-712 method does.
417
+ * writes (e.g. `execute_set_username`), or `query_*` for signed reads. Unlike the EIP-712 method,
418
+ * these values never carry the `mobile:` prefix. Protected image reads use `feed_image` or
419
+ * `feed_comment_image` without a route prefix; malformed multipart uploads use `execute_image_upload`.
224
420
  */
225
421
  export type MobileServerRequestType =
422
+ | 'feed_image'
423
+ | 'feed_comment_image'
424
+ | 'execute_image_upload'
425
+ | `query_${MobileServerSignedQueryRequestType}`
226
426
  | `public_query_${MobileServerPublicQueryRequestType}`
227
427
  | `public_execute_${MobileServerPublicExecuteRequestType}`
228
428
  | `execute_${MobileServerExecuteRequestType}`;
@@ -0,0 +1,45 @@
1
+ import { afterEach, describe, expect, it, jest } from '@jest/globals';
2
+ import { buildMobileFeedImageMultipart } from './buildMobileFeedImageMultipart';
3
+
4
+ describe('buildMobileFeedImageMultipart', () => {
5
+ afterEach(() => {
6
+ jest.restoreAllMocks();
7
+ });
8
+
9
+ it('keeps multipart overhead fixed across timestamp and random boundary lengths', () => {
10
+ const payload = '{"type":"create_feed_post_image_uploads"}';
11
+ const fileBytes = new Uint8Array([0, 1, 255]);
12
+ const expected = buildMobileFeedImageMultipart(payload, fileBytes);
13
+ for (const timestamp of [0, 1_700_000_000_000, 8_640_000_000_000_000]) {
14
+ for (const random of [0, 0.000001, 0.5, 0.999999]) {
15
+ jest.spyOn(Date, 'now').mockReturnValue(timestamp);
16
+ jest.spyOn(Math, 'random').mockReturnValue(random);
17
+ const actual = buildMobileFeedImageMultipart(payload, fileBytes);
18
+ expect(actual.body.byteLength).toBe(expected.body.byteLength);
19
+ expect(actual.contentType.length).toBe(expected.contentType.length);
20
+ }
21
+ }
22
+ });
23
+
24
+ it('emits payload and file parts with a boundary Content-Type', () => {
25
+ const fileBytes = new Uint8Array([0, 1, 127, 128, 255, 13, 10]);
26
+ const { body, contentType } = buildMobileFeedImageMultipart(
27
+ '{"type":"create_feed_post_image_uploads"}',
28
+ fileBytes,
29
+ );
30
+ const text = String.fromCharCode(...body);
31
+ expect(contentType.startsWith('multipart/form-data; boundary=')).toBe(true);
32
+ expect(text).toContain('name="payload"');
33
+ expect(text).toContain('name="file"; filename="image"');
34
+ expect(text).toContain('{"type":"create_feed_post_image_uploads"}');
35
+ const boundary = contentType.split('boundary=')[1];
36
+ const fileStart = text.indexOf('\r\n\r\n', text.indexOf('name="file"')) + 4;
37
+ expect(body.slice(fileStart, fileStart + fileBytes.length)).toEqual(
38
+ fileBytes,
39
+ );
40
+ expect(text.slice(fileStart + fileBytes.length)).toBe(
41
+ `\r\n--${boundary}--\r\n`,
42
+ );
43
+ expect(text.startsWith(`--${boundary}\r\n`)).toBe(true);
44
+ });
45
+ });
@@ -0,0 +1,36 @@
1
+ import { concatBytes, stringToBytes } from 'viem';
2
+
3
+ /**
4
+ * Builds a multipart/form-data body for feed image uploads without relying on DOM FormData/Blob.
5
+ * Parts are exactly `payload` (JSON text) and `file` (raw bytes), matching the mobile execute contract.
6
+ * @param payloadJson - Stringified signed execute body.
7
+ * @param fileBytes - Original image bytes.
8
+ * @returns Raw multipart body and its Content-Type header value including boundary.
9
+ */
10
+ export function buildMobileFeedImageMultipart(
11
+ payloadJson: string,
12
+ fileBytes: Uint8Array,
13
+ ): { body: Uint8Array; contentType: string } {
14
+ // Fixed-length boundaries keep multipart overhead identical for the pre-signing size check and upload.
15
+ const boundary = `----nadoFeedImage${Date.now().toString(16).padStart(14, '0')}${Math.floor(
16
+ Math.random() * 1e6,
17
+ )
18
+ .toString(16)
19
+ .padStart(5, '0')}`;
20
+ const preamble =
21
+ `--${boundary}\r\n` +
22
+ 'Content-Disposition: form-data; name="payload"\r\n' +
23
+ 'Content-Type: application/json\r\n\r\n' +
24
+ `${payloadJson}\r\n` +
25
+ `--${boundary}\r\n` +
26
+ 'Content-Disposition: form-data; name="file"; filename="image"\r\n' +
27
+ 'Content-Type: application/octet-stream\r\n\r\n';
28
+ return {
29
+ body: concatBytes([
30
+ stringToBytes(preamble),
31
+ fileBytes,
32
+ stringToBytes(`\r\n--${boundary}--\r\n`),
33
+ ]),
34
+ contentType: `multipart/form-data; boundary=${boundary}`,
35
+ };
36
+ }
package/src/utils/feed.ts CHANGED
@@ -4,6 +4,9 @@
4
4
  */
5
5
  export const MOBILE_FEED_MAX_PAGE_SIZE = 50;
6
6
 
7
+ /** Maximum feed image upload request size, including the signed payload and multipart framing (2 MiB). */
8
+ export const MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES = 2 * 1024 * 1024;
9
+
7
10
  /**
8
11
  * Lowest minimum notional the backend accepts, in whole dollars. Filtered requests below this fail with
9
12
  * `INVALID_FEED_FILTER`; omitting the filter entirely returns the unfiltered feed.