@nadohq/mobile-client 0.65.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 (207) hide show
  1. package/README.md +107 -8
  2. package/dist/{MobileClient-CfVZXTcz.cjs → MobileClient-M4oC4lrX.cjs} +258 -16
  3. package/dist/MobileClient-M4oC4lrX.cjs.map +1 -0
  4. package/dist/MobileClient.cjs +1 -1
  5. package/dist/MobileClient.d.cts +146 -16
  6. package/dist/MobileClient.d.cts.map +1 -1
  7. package/dist/MobileClient.d.ts +146 -16
  8. package/dist/MobileClient.d.ts.map +1 -1
  9. package/dist/MobileClient.js +258 -16
  10. package/dist/MobileClient.js.map +1 -1
  11. package/dist/{MobileServerFailureError-BZVwlsMg.d.ts → MobileServerFailureError-C9iqNsxI.d.ts} +2 -3
  12. package/dist/MobileServerFailureError-C9iqNsxI.d.ts.map +1 -0
  13. package/dist/{MobileServerFailureError-CbtK8kD4.d.cts → MobileServerFailureError-MtS2reel.d.cts} +2 -3
  14. package/dist/MobileServerFailureError-MtS2reel.d.cts.map +1 -0
  15. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.cts +15 -0
  16. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.cts.map +1 -0
  17. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.ts +15 -0
  18. package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.ts.map +1 -0
  19. package/dist/{buildSignedMobileRequest-UeeWdYGU.d.ts → buildSignedMobileRequest-BR-KJhIF.d.ts} +2 -2
  20. package/dist/{buildSignedMobileRequest-UeeWdYGU.d.ts.map → buildSignedMobileRequest-BR-KJhIF.d.ts.map} +1 -1
  21. package/dist/{buildSignedMobileRequest-C1v0flCR.d.cts → buildSignedMobileRequest-DyKCK34Y.d.cts} +2 -2
  22. package/dist/{buildSignedMobileRequest-C1v0flCR.d.cts.map → buildSignedMobileRequest-DyKCK34Y.d.cts.map} +1 -1
  23. package/dist/{canonicalize-5eeZrkzQ.d.ts → canonicalize-Bv6UIAbR.d.ts} +2 -2
  24. package/dist/canonicalize-Bv6UIAbR.d.ts.map +1 -0
  25. package/dist/{canonicalize-CBaZprTo.d.cts → canonicalize-CWh3XZzj.d.cts} +2 -2
  26. package/dist/canonicalize-CWh3XZzj.d.cts.map +1 -0
  27. package/dist/{clientTypes-C9dJufxk.d.ts → clientTypes-BUn5_OzK.d.ts} +297 -20
  28. package/dist/clientTypes-BUn5_OzK.d.ts.map +1 -0
  29. package/dist/{clientTypes-_mEgzmNs.d.cts → clientTypes-DOpUcu80.d.cts} +297 -20
  30. package/dist/clientTypes-DOpUcu80.d.cts.map +1 -0
  31. package/dist/dataMappers.cjs +203 -5
  32. package/dist/dataMappers.cjs.map +1 -1
  33. package/dist/dataMappers.d.cts +70 -7
  34. package/dist/dataMappers.d.cts.map +1 -1
  35. package/dist/dataMappers.d.ts +70 -7
  36. package/dist/dataMappers.d.ts.map +1 -1
  37. package/dist/dataMappers.js +192 -6
  38. package/dist/dataMappers.js.map +1 -1
  39. package/dist/{eip712MethodByType-D8jLoxDu.d.cts → eip712MethodByType-CJ6BoayT.d.cts} +2 -2
  40. package/dist/eip712MethodByType-CJ6BoayT.d.cts.map +1 -0
  41. package/dist/{eip712MethodByType-DcUh8h-l.d.ts → eip712MethodByType-Dx4mvgni.d.ts} +2 -2
  42. package/dist/eip712MethodByType-Dx4mvgni.d.ts.map +1 -0
  43. package/dist/{feed-DTJlsg8W.d.ts → feed-DErOLaoY.d.cts} +4 -2
  44. package/dist/feed-DErOLaoY.d.cts.map +1 -0
  45. package/dist/{feed-DTJlsg8W.d.cts → feed-DErOLaoY.d.ts} +4 -2
  46. package/dist/feed-DErOLaoY.d.ts.map +1 -0
  47. package/dist/index.cjs +7 -2
  48. package/dist/index.d.cts +14 -16
  49. package/dist/index.d.ts +14 -16
  50. package/dist/index.js +4 -3
  51. package/dist/{mobileErrorCodes-CmjYEIYm.d.ts → mobileErrorCodes-vD6rbFuF.d.cts} +8 -3
  52. package/dist/mobileErrorCodes-vD6rbFuF.d.cts.map +1 -0
  53. package/dist/{mobileErrorCodes-CmjYEIYm.d.cts → mobileErrorCodes-vD6rbFuF.d.ts} +8 -3
  54. package/dist/mobileErrorCodes-vD6rbFuF.d.ts.map +1 -0
  55. package/dist/{payloadHash-DhHmgRqL.d.cts → payloadHash-CdkF2Ocr.d.cts} +2 -2
  56. package/dist/payloadHash-CdkF2Ocr.d.cts.map +1 -0
  57. package/dist/{payloadHash-E1_8fpLW.d.ts → payloadHash-HD29K77M.d.ts} +2 -2
  58. package/dist/payloadHash-HD29K77M.d.ts.map +1 -0
  59. package/dist/{serverExecuteTypes-B-OJok19.d.cts → serverExecuteTypes-5JyyIXRK.d.ts} +21 -5
  60. package/dist/serverExecuteTypes-5JyyIXRK.d.ts.map +1 -0
  61. package/dist/{serverExecuteTypes-BwWGspOg.d.ts → serverExecuteTypes-CHrQ9Rtq.d.cts} +21 -5
  62. package/dist/serverExecuteTypes-CHrQ9Rtq.d.cts.map +1 -0
  63. package/dist/{serverModelTypes-CiA-dy1R.d.ts → serverModelTypes-CGUZCi0y.d.cts} +163 -8
  64. package/dist/serverModelTypes-CGUZCi0y.d.cts.map +1 -0
  65. package/dist/{serverModelTypes-CiA-dy1R.d.cts → serverModelTypes-CGUZCi0y.d.ts} +163 -8
  66. package/dist/serverModelTypes-CGUZCi0y.d.ts.map +1 -0
  67. package/dist/{serverResponseGuards-CShiXpHT.d.ts → serverResponseGuards-Bvw8ltYJ.d.ts} +2 -2
  68. package/dist/{serverResponseGuards-CShiXpHT.d.ts.map → serverResponseGuards-Bvw8ltYJ.d.ts.map} +1 -1
  69. package/dist/{serverResponseGuards-BW69PS7O.d.cts → serverResponseGuards-i1njcYKN.d.cts} +2 -2
  70. package/dist/{serverResponseGuards-BW69PS7O.d.cts.map → serverResponseGuards-i1njcYKN.d.cts.map} +1 -1
  71. package/dist/signing/buildSignedMobileRequest.d.cts +1 -1
  72. package/dist/signing/buildSignedMobileRequest.d.ts +1 -1
  73. package/dist/signing/canonicalize.cjs +51 -2
  74. package/dist/signing/canonicalize.cjs.map +1 -1
  75. package/dist/signing/canonicalize.d.cts +1 -1
  76. package/dist/signing/canonicalize.d.ts +1 -1
  77. package/dist/signing/canonicalize.js +51 -2
  78. package/dist/signing/canonicalize.js.map +1 -1
  79. package/dist/signing/eip712MethodByType.cjs +7 -0
  80. package/dist/signing/eip712MethodByType.cjs.map +1 -1
  81. package/dist/signing/eip712MethodByType.d.cts +1 -1
  82. package/dist/signing/eip712MethodByType.d.ts +1 -1
  83. package/dist/signing/eip712MethodByType.js +7 -0
  84. package/dist/signing/eip712MethodByType.js.map +1 -1
  85. package/dist/signing/index.d.cts +5 -5
  86. package/dist/signing/index.d.ts +5 -5
  87. package/dist/signing/payloadHash.cjs +1 -1
  88. package/dist/signing/payloadHash.d.cts +1 -1
  89. package/dist/signing/payloadHash.d.ts +1 -1
  90. package/dist/signing/payloadHash.js +1 -1
  91. package/dist/signing/types.d.cts +1 -1
  92. package/dist/signing/types.d.ts +1 -1
  93. package/dist/types/MobileServerFailureError.d.cts +1 -1
  94. package/dist/types/MobileServerFailureError.d.ts +1 -1
  95. package/dist/types/MobileUnsupportedNotificationRouteError.cjs +19 -0
  96. package/dist/types/MobileUnsupportedNotificationRouteError.cjs.map +1 -0
  97. package/dist/types/MobileUnsupportedNotificationRouteError.d.cts +2 -0
  98. package/dist/types/MobileUnsupportedNotificationRouteError.d.ts +2 -0
  99. package/dist/types/MobileUnsupportedNotificationRouteError.js +18 -0
  100. package/dist/types/MobileUnsupportedNotificationRouteError.js.map +1 -0
  101. package/dist/types/clientTypes.d.cts +2 -2
  102. package/dist/types/clientTypes.d.ts +2 -2
  103. package/dist/types/index.cjs +4 -0
  104. package/dist/types/index.d.cts +8 -9
  105. package/dist/types/index.d.ts +8 -9
  106. package/dist/types/index.js +3 -2
  107. package/dist/types/mobileErrorCodes.cjs +11 -1
  108. package/dist/types/mobileErrorCodes.cjs.map +1 -1
  109. package/dist/types/mobileErrorCodes.d.cts +1 -1
  110. package/dist/types/mobileErrorCodes.d.ts +1 -1
  111. package/dist/types/mobileErrorCodes.js +11 -1
  112. package/dist/types/mobileErrorCodes.js.map +1 -1
  113. package/dist/types/serverBaseTypes.d.cts +1 -1
  114. package/dist/types/serverBaseTypes.d.ts +1 -1
  115. package/dist/types/serverExecuteTypes.d.cts +2 -2
  116. package/dist/types/serverExecuteTypes.d.ts +2 -2
  117. package/dist/types/serverModelTypes.cjs +15 -0
  118. package/dist/types/serverModelTypes.cjs.map +1 -1
  119. package/dist/types/serverModelTypes.d.cts +2 -2
  120. package/dist/types/serverModelTypes.d.ts +2 -2
  121. package/dist/types/serverModelTypes.js +14 -1
  122. package/dist/types/serverModelTypes.js.map +1 -1
  123. package/dist/types/serverQueryTypes.d.cts +2 -2
  124. package/dist/types/serverQueryTypes.d.ts +2 -2
  125. package/dist/types/serverRequestTypes.d.cts +2 -2
  126. package/dist/types/serverRequestTypes.d.ts +2 -2
  127. package/dist/types-C9YE4EIt.d.cts +794 -0
  128. package/dist/types-C9YE4EIt.d.cts.map +1 -0
  129. package/dist/types-Cwy1y_9x.d.ts +794 -0
  130. package/dist/types-Cwy1y_9x.d.ts.map +1 -0
  131. package/dist/utils/buildMobileFeedImageMultipart.cjs +31 -0
  132. package/dist/utils/buildMobileFeedImageMultipart.cjs.map +1 -0
  133. package/dist/utils/buildMobileFeedImageMultipart.d.cts +15 -0
  134. package/dist/utils/buildMobileFeedImageMultipart.d.cts.map +1 -0
  135. package/dist/utils/buildMobileFeedImageMultipart.d.ts +15 -0
  136. package/dist/utils/buildMobileFeedImageMultipart.d.ts.map +1 -0
  137. package/dist/utils/buildMobileFeedImageMultipart.js +30 -0
  138. package/dist/utils/buildMobileFeedImageMultipart.js.map +1 -0
  139. package/dist/utils/feed.cjs +3 -0
  140. package/dist/utils/feed.cjs.map +1 -1
  141. package/dist/utils/feed.d.cts +2 -2
  142. package/dist/utils/feed.d.ts +2 -2
  143. package/dist/utils/feed.js +3 -1
  144. package/dist/utils/feed.js.map +1 -1
  145. package/dist/utils/index.cjs +2 -1
  146. package/dist/utils/index.d.cts +3 -3
  147. package/dist/utils/index.d.ts +3 -3
  148. package/dist/utils/index.js +2 -2
  149. package/dist/utils/serverResponseGuards.d.cts +1 -1
  150. package/dist/utils/serverResponseGuards.d.ts +1 -1
  151. package/package.json +3 -3
  152. package/src/MobileClient.ts +388 -11
  153. package/src/dataMappers.test.ts +108 -2
  154. package/src/dataMappers.ts +253 -5
  155. package/src/feedImages.test.ts +309 -0
  156. package/src/notifications.test.ts +950 -0
  157. package/src/signing/canonicalize.ts +66 -0
  158. package/src/signing/eip712MethodByType.ts +10 -0
  159. package/src/signing/signing.test.ts +16 -1
  160. package/src/signing/types.ts +51 -9
  161. package/src/socialFeed.test.ts +38 -2
  162. package/src/types/MobileUnsupportedNotificationRouteError.ts +16 -0
  163. package/src/types/clientTypes.ts +372 -16
  164. package/src/types/index.ts +1 -0
  165. package/src/types/mobileErrorCodes.ts +10 -0
  166. package/src/types/serverExecuteTypes.ts +20 -0
  167. package/src/types/serverModelTypes.ts +205 -6
  168. package/src/types/serverQueryTypes.ts +74 -5
  169. package/src/types/serverRequestTypes.ts +101 -12
  170. package/src/utils/buildMobileFeedImageMultipart.test.ts +45 -0
  171. package/src/utils/buildMobileFeedImageMultipart.ts +36 -0
  172. package/src/utils/feed.ts +3 -0
  173. package/dist/MobileClient-CfVZXTcz.cjs.map +0 -1
  174. package/dist/MobileServerFailureError-BZVwlsMg.d.ts.map +0 -1
  175. package/dist/MobileServerFailureError-CbtK8kD4.d.cts.map +0 -1
  176. package/dist/canonicalize-5eeZrkzQ.d.ts.map +0 -1
  177. package/dist/canonicalize-CBaZprTo.d.cts.map +0 -1
  178. package/dist/clientTypes-C9dJufxk.d.ts.map +0 -1
  179. package/dist/clientTypes-_mEgzmNs.d.cts.map +0 -1
  180. package/dist/eip712MethodByType-D8jLoxDu.d.cts.map +0 -1
  181. package/dist/eip712MethodByType-DcUh8h-l.d.ts.map +0 -1
  182. package/dist/feed-DTJlsg8W.d.cts.map +0 -1
  183. package/dist/feed-DTJlsg8W.d.ts.map +0 -1
  184. package/dist/mobileErrorCodes-CmjYEIYm.d.cts.map +0 -1
  185. package/dist/mobileErrorCodes-CmjYEIYm.d.ts.map +0 -1
  186. package/dist/payloadHash-DhHmgRqL.d.cts.map +0 -1
  187. package/dist/payloadHash-E1_8fpLW.d.ts.map +0 -1
  188. package/dist/serverBaseTypes-B5J1_TyC.d.cts +0 -25
  189. package/dist/serverBaseTypes-B5J1_TyC.d.cts.map +0 -1
  190. package/dist/serverBaseTypes-DnLzsdm-.d.ts +0 -25
  191. package/dist/serverBaseTypes-DnLzsdm-.d.ts.map +0 -1
  192. package/dist/serverExecuteTypes-B-OJok19.d.cts.map +0 -1
  193. package/dist/serverExecuteTypes-BwWGspOg.d.ts.map +0 -1
  194. package/dist/serverModelTypes-CiA-dy1R.d.cts.map +0 -1
  195. package/dist/serverModelTypes-CiA-dy1R.d.ts.map +0 -1
  196. package/dist/serverQueryTypes-CJcjLB7n.d.ts +0 -283
  197. package/dist/serverQueryTypes-CJcjLB7n.d.ts.map +0 -1
  198. package/dist/serverQueryTypes-V1f9yE7L.d.cts +0 -283
  199. package/dist/serverQueryTypes-V1f9yE7L.d.cts.map +0 -1
  200. package/dist/serverRequestTypes-CRlkNSu5.d.cts +0 -270
  201. package/dist/serverRequestTypes-CRlkNSu5.d.cts.map +0 -1
  202. package/dist/serverRequestTypes-DZoOhV2o.d.ts +0 -270
  203. package/dist/serverRequestTypes-DZoOhV2o.d.ts.map +0 -1
  204. package/dist/types-BiRmH5Iv.d.cts +0 -108
  205. package/dist/types-BiRmH5Iv.d.cts.map +0 -1
  206. package/dist/types-DoJuq0Ij.d.ts +0 -108
  207. package/dist/types-DoJuq0Ij.d.ts.map +0 -1
@@ -1,10 +1,14 @@
1
- import { mapMobileAvatarPreset, mapMobileAvatarSelectionToServer, mapMobileAvatarUpload, mapMobileFeedPage, mapMobileFollowBatchResult, mapMobileFollowListPage, mapMobileFollowListParamsToServer, mapMobileFollowMutationResult, mapMobileNotificationPreferences, mapMobileNotificationPreferencesToServer, mapMobileProfileSearchPage, mapMobileProfileSearchParamsToServer, mapMobileProfilesIncludeToServer, mapMobilePublicProfile, mapMobileRegisteredWallet, mapMobileSocialFeedActionResolutionResult, mapMobileSocialFeedCommentResult, mapMobileSocialFeedCommentsPage, mapMobileSocialFeedDrawingMutationResult, mapMobileSocialFeedDrawingResult, mapMobileSocialFeedItem, mapMobileSocialFeedItemResponse, mapMobileSocialFeedLikeResult, mapMobileSocialFeedListParamsToServer, mapMobileSocialFeedMentionToServer, mapMobileSocialFeedPage, mapMobileSocialFeedPositionChart, mapMobileSocialFeedPositionHistory, mapMobileSocialFeedPositionResolutionResult, mapMobileSocialFeedPositionsPage, mapMobileSocialFeedPresence, mapMobileSocialFeedRankedPage, mapMobileSocialFeedReadParamsToServer, mapMobileSocialFeedTopTradersPage, mapMobileSocialFeedUpdates, mapMobileSocialFeedViewsResult, mapMobileSocialFeedWatchers } from "./dataMappers.js";
1
+ import { mapMobileAvatarPreset, mapMobileAvatarSelectionToServer, mapMobileAvatarUpload, mapMobileFeedPage, mapMobileFollowBatchResult, mapMobileFollowListPage, mapMobileFollowListParamsToServer, mapMobileFollowMutationResult, mapMobileNotificationCapabilitiesToServer, mapMobileNotificationInboxV2, mapMobileNotificationPreferences, mapMobileNotificationPreferencesToServer, mapMobileNotificationRegistrationV2, mapMobileNotificationSettingsToServer, mapMobileNotificationSettingsV2, mapMobileNotificationSubscriptions, mapMobileNotificationSubscriptionsUpdateToServer, mapMobileProductEventToServer, mapMobileProfileSearchPage, mapMobileProfileSearchParamsToServer, mapMobileProfilesIncludeToServer, mapMobilePublicProfile, mapMobileRegisteredWallet, mapMobileSocialFeedActionResolutionResult, mapMobileSocialFeedCommentResult, mapMobileSocialFeedCommentsPage, mapMobileSocialFeedDrawingMutationResult, mapMobileSocialFeedDrawingResult, mapMobileSocialFeedImage, mapMobileSocialFeedItem, mapMobileSocialFeedItemResponse, mapMobileSocialFeedLikeResult, mapMobileSocialFeedListParamsToServer, mapMobileSocialFeedMentionToServer, mapMobileSocialFeedPage, mapMobileSocialFeedPositionChart, mapMobileSocialFeedPositionHistory, mapMobileSocialFeedPositionResolutionResult, mapMobileSocialFeedPositionsPage, mapMobileSocialFeedPresence, mapMobileSocialFeedRankedPage, mapMobileSocialFeedReadParamsToServer, mapMobileSocialFeedTopTradersPage, mapMobileSocialFeedUpdates, mapMobileSocialFeedViewsResult, mapMobileSocialFeedWatchers } from "./dataMappers.js";
2
+ import { getMobileNonce } from "./signing/nonce.js";
2
3
  import { buildSignedMobileRequest } from "./signing/buildSignedMobileRequest.js";
3
4
  import "./signing/index.js";
4
5
  import { MobileServerFailureError } from "./types/MobileServerFailureError.js";
6
+ import { buildMobileFeedImageMultipart } from "./utils/buildMobileFeedImageMultipart.js";
7
+ import { MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES } from "./utils/feed.js";
5
8
  import { isMobileServerFailureResponse, isMobileServerSuccessResponse } from "./utils/serverResponseGuards.js";
6
9
  import { WalletNotProvidedError, getNadoClientTypeHeaders, subaccountToHex } from "@nadohq/shared";
7
10
  import axios from "axios";
11
+ import { bytesToString, keccak256, zeroHash } from "viem";
8
12
  //#region src/MobileClient.ts
9
13
  /**
10
14
  * Client for the Nado mobile service API: usernames, bios, avatars, public profile lookups, the global
@@ -255,7 +259,9 @@ var MobileClient = class {
255
259
  /**
256
260
  * Reads one item visible to viewAs, including that account's own hidden content.
257
261
  * Creates an item session directly when sessionId is omitted.
258
- * @param params - Item UUID, preview limit, and optional existing session/read identity.
262
+ * Pass {@link GetMobileFeedItemParams.viewEventId} when the user navigates into the detail so the
263
+ * subsequent {@link recordFeedViews} call can count that visit; omit it for prefetch.
264
+ * @param params - Item UUID, optional detail-visit event, preview limit, and optional existing session/read identity.
259
265
  * @returns The complete item and authorized reading session.
260
266
  * @throws {MobileServerFailureError} On inaccessible content or session mismatch/expiry.
261
267
  * @throws {MobileUnsupportedFeedItemError} If the service returns an unsupported item kind.
@@ -264,6 +270,7 @@ var MobileClient = class {
264
270
  const body = {
265
271
  type: "feed_item",
266
272
  item_id: params.itemId,
273
+ view_event_id: params.viewEventId,
267
274
  comment_preview_limit: params.commentPreviewLimit,
268
275
  session_id: params.sessionId,
269
276
  ...mapMobileSocialFeedReadParamsToServer(params)
@@ -301,6 +308,7 @@ var MobileClient = class {
301
308
  *
302
309
  * @throws {MobileServerFailureError} With error code `INVALID_EXPO_TOKEN` if the token is malformed, or is
303
310
  * not currently registered to a wallet.
311
+ * @deprecated Use {@link getNotificationSettingsV2} instead.
304
312
  */
305
313
  async getNotificationPreferences(params) {
306
314
  const body = {
@@ -393,6 +401,40 @@ var MobileClient = class {
393
401
  return mapMobileSocialFeedDrawingResult(await this.publicQuery(body));
394
402
  }
395
403
  /**
404
+ * Resolves a backend feed image path against this client's mobile gateway URL.
405
+ * @param path - Backend path from image metadata, rooted at /v1/mobile or the mobile service root.
406
+ * @returns An absolute URL suitable for authenticated fetches.
407
+ */
408
+ resolveFeedImageUrl(path) {
409
+ return `${this.opts.url}${path.replace(/^\/v1\/mobile(?=\/)/, "")}`;
410
+ }
411
+ /**
412
+ * Prepares a protected image request for native image components without downloading or encoding bytes.
413
+ * Does not count as a detail visit or recorded view.
414
+ * @param params - Image path from metadata plus the original session credentials.
415
+ * @returns Absolute URL and headers; pass them as the image source's URI and headers.
416
+ */
417
+ getFeedImageRequest(params) {
418
+ return {
419
+ url: this.resolveFeedImageUrl(params.path),
420
+ headers: {
421
+ "x-feed-session-id": params.sessionId,
422
+ "x-feed-viewer-token": params.viewerToken
423
+ }
424
+ };
425
+ }
426
+ /**
427
+ * Fetches protected feed image bytes using the reading session that fully delivered the parent item.
428
+ * Does not count as a detail visit or recorded view.
429
+ * @param params - Image path from metadata plus the original session credentials.
430
+ * @returns Raw image bytes.
431
+ * @throws {MobileServerFailureError} On session, permission, or availability errors.
432
+ */
433
+ async getFeedImageBytes(params) {
434
+ const { url, headers } = this.getFeedImageRequest(params);
435
+ return this.publicGetBytes(url, headers);
436
+ }
437
+ /**
396
438
  * Reads a comment thread with an optional anchor and bidirectional pagination.
397
439
  * Independent reads create a public-only session; reused sessions retain their original scope.
398
440
  * @param params - Root item, optional anchor or cursor (mutually exclusive), page size, and read perspective.
@@ -475,6 +517,57 @@ var MobileClient = class {
475
517
  return mapMobileSocialFeedWatchers(await this.publicQuery(body));
476
518
  }
477
519
  /**
520
+ * Reads the token's latest registration generation and saved capabilities, including legacy v1 registrations.
521
+ * @param params - Active Expo token credential; no wallet signature is needed.
522
+ * @returns Saved generation as an opaque string and the complete capability declaration.
523
+ * @throws {MobileServerFailureError} If the token is invalid or inactive (`INVALID_EXPO_TOKEN`).
524
+ */
525
+ async getNotificationRegistrationV2(params) {
526
+ return mapMobileNotificationRegistrationV2(await this.publicQuery({
527
+ type: "notification_registration_v2",
528
+ expo_token: params.expoToken
529
+ }));
530
+ }
531
+ /**
532
+ * Reads the wallet's full v2 settings document, including legacy preference mappings.
533
+ * @param params - Active Expo token credential. Before displaying settings, compare the wallet returned by
534
+ * {@link MobileClient.getRegisteredWallet} with the connected wallet (case-insensitively).
535
+ * @returns CamelCase settings with the current settings revision.
536
+ * @throws {MobileServerFailureError} If the token is invalid or inactive (`INVALID_EXPO_TOKEN`).
537
+ */
538
+ async getNotificationSettingsV2(params) {
539
+ return mapMobileNotificationSettingsV2(await this.publicQuery({
540
+ type: "notification_settings_v2",
541
+ expo_token: params.expoToken
542
+ }));
543
+ }
544
+ /**
545
+ * Reads wallet market subscriptions and the signing Identity's enabled trader bells.
546
+ * @param params - Wallet authentication context; no Expo token is needed.
547
+ * @returns Subscriptions, import state, and the independent subscription revision.
548
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
549
+ * @throws {MobileServerFailureError} If authentication or the query fails.
550
+ */
551
+ async getNotificationSubscriptions(params) {
552
+ const request = await this.getSignedRequest("notification_subscriptions", params, {});
553
+ return mapMobileNotificationSubscriptions(await this.query(request));
554
+ }
555
+ /**
556
+ * Reads private accepted notification intents, not delivery receipts or read states.
557
+ * @param params - Wallet authentication and optional cursor/page size (1-50, default 20).
558
+ * @returns A camelCase page; discard cached pages and cursors when switching wallets.
559
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
560
+ * @throws {MobileServerFailureError} If authentication or pagination validation fails.
561
+ * @throws {MobileUnsupportedNotificationRouteError} If a notification has an unsupported route name.
562
+ */
563
+ async getNotificationInboxV2(params) {
564
+ const request = await this.getSignedRequest("notification_inbox_v2", params, {
565
+ cursor: params.cursor ?? null,
566
+ limit: params.limit ?? null
567
+ });
568
+ return mapMobileNotificationInboxV2(await this.query(request));
569
+ }
570
+ /**
478
571
  * Unregisters an Expo push token, stopping delivery to that device. Unsigned, so it still works at logout
479
572
  * when a wallet signature may no longer be obtainable. Idempotent: unregistering an inactive or unknown
480
573
  * well-formed token succeeds.
@@ -502,6 +595,7 @@ var MobileClient = class {
502
595
  *
503
596
  * @throws {MobileServerFailureError} With error code `INVALID_PREFERENCES` if those rules are violated, or
504
597
  * `INVALID_EXPO_TOKEN` if the token is malformed or is not currently registered to a wallet.
598
+ * @deprecated Use {@link updateNotificationSettingsV2} instead.
505
599
  */
506
600
  async updateNotificationPreferences(params) {
507
601
  const body = {
@@ -512,20 +606,39 @@ var MobileClient = class {
512
606
  return this.publicExecute(body);
513
607
  }
514
608
  /**
515
- * Reports qualified exposures without signing. Ordinary reads and root previews do not count as exposures.
516
- * The caller must satisfy the session's viewTracking requirements before reporting an item.
517
- * @param params - Original reading session and viewer token, plus one to fifty fully delivered, readable,
518
- * interactive item IDs. The service deduplicates repeated exposures.
519
- * @returns Separate lists of newly accepted and already-counted item IDs.
520
- * @throws {MobileServerFailureError} On invalid parameters, session mismatch or expiry, or any ineligible item.
521
- * A rejected batch is not partially counted. Acquire a new session after expiry and re-evaluate exposure eligibility.
609
+ * Replaces all v2 settings fields using optimistic concurrency; legacy overlapping preferences are synced.
610
+ * @param params - Active Expo token, latest settings revision, and complete replacement settings.
611
+ * @returns The saved settings document with its incremented revision.
612
+ * @throws {MobileServerFailureError} On invalid token/settings or revision conflict (`NOTIFICATION_REVISION_CONFLICT`). Re-read and
613
+ * merge only the user's current change before retrying; never blindly replay a stale document.
614
+ */
615
+ async updateNotificationSettingsV2(params) {
616
+ return mapMobileNotificationSettingsV2(await this.publicExecute({
617
+ type: "update_notification_settings_v2",
618
+ expo_token: params.expoToken,
619
+ expected_revision: params.expectedRevision,
620
+ settings: mapMobileNotificationSettingsToServer(params.settings)
621
+ }));
622
+ }
623
+ /**
624
+ * Reports a detail visit without signing. Feed-list card impressions and previews do not count.
625
+ * After the primary detail target is shown in the foreground, send the same viewEventId previously
626
+ * registered through {@link getFeedItem}, together with that response's sessionId and viewerToken.
627
+ * Reuse the event ID on retries for the same visit; generate a new one only after leaving and re-entering.
628
+ * @param params - Original reading session and viewer token, the registered detail-visit event, and exactly
629
+ * one fully delivered, readable detail-target item ID.
630
+ * @returns Separate lists of newly accepted and already-counted item IDs for that event.
631
+ * @throws {MobileServerFailureError} On invalid parameters, an unregistered or rebound event
632
+ * (`SOCIAL_FEED_VIEW_EVENT_REBOUND`), session mismatch or expiry, or an ineligible item.
633
+ * Acquire a new session after expiry, re-register the same event via getFeedItem, then retry.
522
634
  */
523
635
  async recordFeedViews(params) {
524
636
  const body = {
525
637
  type: "record_feed_views",
526
638
  session_id: params.sessionId,
527
- item_ids: params.itemIds,
528
- viewer_token: params.viewerToken
639
+ viewer_token: params.viewerToken,
640
+ view_event_id: params.viewEventId,
641
+ item_ids: [params.itemId]
529
642
  };
530
643
  return mapMobileSocialFeedViewsResult(await this.publicExecute(body));
531
644
  }
@@ -616,11 +729,13 @@ var MobileClient = class {
616
729
  }
617
730
  /**
618
731
  * Registers an Expo push token for the wallet, transferring active ownership of the token if another
619
- * wallet had registered it. Idempotent per `(wallet, token)`.
732
+ * wallet had registered it. Each registration advances its generation and cancels old pending deliveries.
733
+ * This legacy method replaces capabilities with v1; use registerExpoTokenV2 consistently after upgrading.
620
734
  *
621
735
  * @throws {MobileServerFailureError} With error code `INVALID_EXPO_TOKEN` if the token is not a valid Expo
622
736
  * push token, or `INVALID_DEVICE_METADATA` if `locale` (max 35 chars) or `appVersion` (max 64 chars) is
623
737
  * too long.
738
+ * @deprecated Use {@link registerExpoTokenV2} instead.
624
739
  */
625
740
  async registerExpoToken(params) {
626
741
  const signedRequest = await this.getSignedRequest("register_expo_token", params, {
@@ -632,6 +747,47 @@ var MobileClient = class {
632
747
  return this.execute(signedRequest);
633
748
  }
634
749
  /**
750
+ * Registers a device with its actual v2 capabilities; do not use repeated registration as a heartbeat.
751
+ * @param params - Wallet authentication, Expo token, metadata, and supported notification types/routes.
752
+ * @returns Success only; query registration separately for its new generation.
753
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
754
+ * @throws {MobileServerFailureError} On `INVALID_EXPO_TOKEN`, `INVALID_DEVICE_METADATA`,
755
+ * `NOTIFICATION_DEVICE_LIMIT` when the wallet already has 32 active devices, or authentication errors.
756
+ */
757
+ async registerExpoTokenV2(params) {
758
+ const request = await this.getSignedRequest("register_expo_token_v2", params, {
759
+ expo_token: params.expoToken,
760
+ platform: params.platform,
761
+ locale: params.locale ?? null,
762
+ app_version: params.appVersion ?? null,
763
+ capabilities: mapMobileNotificationCapabilitiesToServer(params.capabilities)
764
+ });
765
+ return this.execute(request);
766
+ }
767
+ /**
768
+ * Applies exactly one bell, market, or one-time favorites-import operation.
769
+ * @param params - Wallet authentication and subscription update with the latest subscription revision.
770
+ * @returns Success only; re-query subscriptions for the new revision even after a repeated ON/OFF.
771
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
772
+ * @throws {MobileServerFailureError} On `NOTIFICATION_REVISION_CONFLICT`, `INVALID_NOTIFICATION_REQUEST`, or
773
+ * `INVALID_IDENTITY_TARGET`.
774
+ */
775
+ async updateNotificationSubscriptions(params) {
776
+ const request = await this.getSignedRequest("update_notification_subscriptions", params, mapMobileNotificationSubscriptionsUpdateToServer(params.update));
777
+ return this.execute(request);
778
+ }
779
+ /**
780
+ * Atomically records 1-50 analytics events after the user has consented to analytics.
781
+ * @param params - Wallet authentication and events with stable UUIDs and actual millisecond timestamps.
782
+ * @returns Success only; reuse event IDs on retries. Notification clicks do not mark an inbox item as read.
783
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
784
+ * @throws {MobileServerFailureError} If any event, timestamp, batch size, or notification ownership is invalid.
785
+ */
786
+ async recordProductEvents(params) {
787
+ const request = await this.getSignedRequest("record_product_events", params, { events: params.events.map(mapMobileProductEventToServer) });
788
+ return this.execute(request);
789
+ }
790
+ /**
635
791
  * Sets whether the signing subaccount follows a Profile. Both directions are idempotent: following again
636
792
  * keeps the original relationship creation time, so it does not move the account in recency order, and
637
793
  * unfollowing a relationship that does not exist succeeds with `isFollowing: false`. Unfollowing deletes
@@ -696,11 +852,41 @@ var MobileClient = class {
696
852
  action_id: params.actionId,
697
853
  text: params.text,
698
854
  mentions: params.mentions.map(mapMobileSocialFeedMentionToServer),
699
- drawing_data_json: params.drawingDataJson
855
+ drawing_data_json: params.drawingDataJson,
856
+ image_ids: params.imageIds
700
857
  });
701
858
  return mapMobileSocialFeedItem((await this.execute(request)).item);
702
859
  }
703
860
  /**
861
+ * Uploads one static JPEG/PNG for a later {@link createFeedPost} via multipart execute.
862
+ * The whole HTTP request must stay within 2 MiB including signature overhead; upload one file per call
863
+ * and bind up to nine ready IDs at publication. There is no complete/PUT step — success means ready.
864
+ * @param params - Author subaccount and signing options, plus the original file bytes.
865
+ * @returns Ready image metadata, including original and thumbnail paths.
866
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
867
+ * @throws {RangeError} If the complete multipart request exceeds {@link MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES}.
868
+ * @throws {MobileServerFailureError} On authentication, format/size/hash errors (`INVALID_SOCIAL_FEED_IMAGE`),
869
+ * or when publishing is disabled (`SERVICE_UNAVAILABLE`), or image storage is unavailable
870
+ * (`SOCIAL_FEED_DATA_UNAVAILABLE`, 6320, HTTP 503).
871
+ */
872
+ async createFeedPostImageUpload(params) {
873
+ return this.createFeedImageUpload("create_feed_post_image_uploads", params);
874
+ }
875
+ /**
876
+ * Uploads one static JPEG/PNG for a later {@link createFeedComment} via multipart execute.
877
+ * Same size and readiness rules as {@link createFeedPostImageUpload}; comment text remains required.
878
+ * @param params - Author subaccount and signing options, plus the original file bytes.
879
+ * @returns Ready image metadata, including original and thumbnail paths.
880
+ * @throws {WalletNotProvidedError} If neither a linked signer nor a default wallet is configured.
881
+ * @throws {RangeError} If the complete multipart request exceeds {@link MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES}.
882
+ * @throws {MobileServerFailureError} On authentication, format/size/hash errors (`INVALID_SOCIAL_FEED_IMAGE`),
883
+ * or when comments are disabled (`SERVICE_UNAVAILABLE`), or image storage is unavailable
884
+ * (`SOCIAL_FEED_DATA_UNAVAILABLE`, 6320, HTTP 503).
885
+ */
886
+ async createFeedCommentImageUpload(params) {
887
+ return this.createFeedImageUpload("create_feed_comment_image_uploads", params);
888
+ }
889
+ /**
704
890
  * First attaches a drawing to an owned post or trade card while the author still holds its position.
705
891
  * The original JSON is signed unchanged; false and zero are valid drawing documents.
706
892
  * For an exact retry after a timeout, generate a nonce up front with {@link getMobileNonce} and reuse
@@ -756,7 +942,8 @@ var MobileClient = class {
756
942
  reply_to_item_id: params.replyToItemId,
757
943
  text: params.text,
758
944
  mentions: params.mentions.map(mapMobileSocialFeedMentionToServer),
759
- attached_position_id: params.attachedPositionId
945
+ attached_position_id: params.attachedPositionId,
946
+ image_ids: params.imageIds
760
947
  });
761
948
  return mapMobileSocialFeedCommentResult(await this.execute(request));
762
949
  }
@@ -798,18 +985,73 @@ var MobileClient = class {
798
985
  this.checkServerStatus(response);
799
986
  return response.data;
800
987
  }
988
+ async publicGetBytes(url, headers) {
989
+ const response = await this.axiosInstance.get(url, {
990
+ responseType: "arraybuffer",
991
+ headers
992
+ });
993
+ if (response.status < 200 || response.status >= 300) {
994
+ const responseText = bytesToString(new Uint8Array(response.data));
995
+ let errorData;
996
+ try {
997
+ errorData = JSON.parse(responseText);
998
+ } catch {
999
+ errorData = responseText;
1000
+ }
1001
+ this.checkResponseStatus({
1002
+ ...response,
1003
+ data: errorData
1004
+ });
1005
+ }
1006
+ return new Uint8Array(response.data);
1007
+ }
801
1008
  async publicExecute(body) {
802
1009
  const response = await this.axiosInstance.post(`${this.opts.url}/public_execute`, body);
803
1010
  this.checkResponseStatus(response);
804
1011
  this.checkServerStatus(response);
805
1012
  return response.data;
806
1013
  }
807
- async execute(body) {
808
- const response = await this.axiosInstance.post(`${this.opts.url}/execute`, body);
1014
+ /**
1015
+ * Sends an authenticated read through the signed query route.
1016
+ * @param body - Canonical inner payload with its signature, sender, and nonce.
1017
+ * @returns The successful query envelope and its type-specific payload.
1018
+ * @throws {MobileServerFailureError} For a structured service failure, including non-2xx responses.
1019
+ */
1020
+ async query(body) {
1021
+ const response = await this.axiosInstance.post(`${this.opts.url}/query`, body);
809
1022
  this.checkResponseStatus(response);
810
1023
  this.checkServerStatus(response);
811
1024
  return response.data;
812
1025
  }
1026
+ async execute(body, fileBytes) {
1027
+ const multipart = fileBytes == null ? void 0 : buildMobileFeedImageMultipart(JSON.stringify(body), fileBytes);
1028
+ if (multipart) this.checkFeedImageRequestSize(multipart.body.byteLength);
1029
+ const response = await this.axiosInstance.post(`${this.opts.url}/execute`, multipart?.body ?? body, multipart ? { headers: { "Content-Type": multipart.contentType } } : void 0);
1030
+ this.checkResponseStatus(response);
1031
+ this.checkServerStatus(response);
1032
+ return response.data;
1033
+ }
1034
+ async createFeedImageUpload(type, params) {
1035
+ const nonce = params.nonce ?? getMobileNonce();
1036
+ const sizePayload = {
1037
+ type,
1038
+ content_hash: zeroHash,
1039
+ signature: `0x${"00".repeat(65)}`,
1040
+ sender: subaccountToHex(params),
1041
+ nonce: nonce.toString()
1042
+ };
1043
+ const overhead = buildMobileFeedImageMultipart(JSON.stringify(sizePayload), new Uint8Array()).body.byteLength;
1044
+ this.checkFeedImageRequestSize(overhead + params.fileBytes.byteLength);
1045
+ const contentHash = keccak256(params.fileBytes);
1046
+ const request = await this.getSignedRequest(type, {
1047
+ ...params,
1048
+ nonce
1049
+ }, { content_hash: contentHash });
1050
+ return mapMobileSocialFeedImage((await this.execute(request, params.fileBytes)).image);
1051
+ }
1052
+ checkFeedImageRequestSize(byteLength) {
1053
+ if (byteLength > 2097152) throw new RangeError(`Feed image upload request exceeds ${MOBILE_FEED_IMAGE_MAX_REQUEST_BYTES} bytes (2 MiB).`);
1054
+ }
813
1055
  /**
814
1056
  * Validates the HTTP status before interpreting the body. Unlike the engine, the mobile backend returns
815
1057
  * failure envelopes with non-2xx statuses (e.g. 404 for `PROFILE_NOT_FOUND`), so a non-2xx response with a