@nadohq/mobile-client 0.54.0 → 0.56.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 (175) hide show
  1. package/README.md +4 -4
  2. package/dist/{MobileClient-BbTaqTzi.cjs → MobileClient-DjNpN7Dw.cjs} +55 -4
  3. package/dist/MobileClient-DjNpN7Dw.cjs.map +1 -0
  4. package/dist/MobileClient.cjs +1 -1
  5. package/dist/MobileClient.d.cts +49 -9
  6. package/dist/MobileClient.d.cts.map +1 -1
  7. package/dist/MobileClient.d.ts +49 -9
  8. package/dist/MobileClient.d.ts.map +1 -1
  9. package/dist/MobileClient.js +55 -4
  10. package/dist/MobileClient.js.map +1 -1
  11. package/dist/{MobileServerFailureError-B2og8e5O.d.ts → MobileServerFailureError-DvtkMAVX.d.ts} +3 -3
  12. package/dist/{MobileServerFailureError-B2og8e5O.d.ts.map → MobileServerFailureError-DvtkMAVX.d.ts.map} +1 -1
  13. package/dist/{MobileServerFailureError-BrLtaHnU.d.cts → MobileServerFailureError-kbMi1Ntc.d.cts} +3 -3
  14. package/dist/{MobileServerFailureError-BrLtaHnU.d.cts.map → MobileServerFailureError-kbMi1Ntc.d.cts.map} +1 -1
  15. package/dist/{buildSignedMobileRequest-CZ-EdxYI.d.cts → buildSignedMobileRequest-DBWN0z0u.d.cts} +2 -2
  16. package/dist/{buildSignedMobileRequest-CZ-EdxYI.d.cts.map → buildSignedMobileRequest-DBWN0z0u.d.cts.map} +1 -1
  17. package/dist/{buildSignedMobileRequest-CoAVSDPx.d.ts → buildSignedMobileRequest-lSIJmG6D.d.ts} +2 -2
  18. package/dist/{buildSignedMobileRequest-CoAVSDPx.d.ts.map → buildSignedMobileRequest-lSIJmG6D.d.ts.map} +1 -1
  19. package/dist/{canonicalize-BC-JICjp.d.ts → canonicalize-Cx3lCVpm.d.ts} +2 -2
  20. package/dist/canonicalize-Cx3lCVpm.d.ts.map +1 -0
  21. package/dist/{canonicalize-0_B6UOxO.d.cts → canonicalize-DNgB8Jsm.d.cts} +2 -2
  22. package/dist/canonicalize-DNgB8Jsm.d.cts.map +1 -0
  23. package/dist/{clientTypes-YF5d8bvg.d.cts → clientTypes-DnPE1zZO.d.cts} +64 -12
  24. package/dist/clientTypes-DnPE1zZO.d.cts.map +1 -0
  25. package/dist/{clientTypes-P4LAjreY.d.ts → clientTypes-ws9CDHw4.d.ts} +64 -12
  26. package/dist/clientTypes-ws9CDHw4.d.ts.map +1 -0
  27. package/dist/dataMappers.cjs +39 -3
  28. package/dist/dataMappers.cjs.map +1 -1
  29. package/dist/dataMappers.d.cts +18 -6
  30. package/dist/dataMappers.d.cts.map +1 -1
  31. package/dist/dataMappers.d.ts +18 -6
  32. package/dist/dataMappers.d.ts.map +1 -1
  33. package/dist/dataMappers.js +37 -4
  34. package/dist/dataMappers.js.map +1 -1
  35. package/dist/{eip712MethodByType-DWtLyPY7.d.ts → eip712MethodByType-Bmu9PYx6.d.ts} +2 -2
  36. package/dist/eip712MethodByType-Bmu9PYx6.d.ts.map +1 -0
  37. package/dist/{eip712MethodByType-sHQ-VTHd.d.cts → eip712MethodByType-T7dfjmC_.d.cts} +2 -2
  38. package/dist/eip712MethodByType-T7dfjmC_.d.cts.map +1 -0
  39. package/dist/index.cjs +5 -1
  40. package/dist/index.d.cts +16 -15
  41. package/dist/index.d.ts +16 -15
  42. package/dist/index.js +2 -1
  43. package/dist/{mobileErrorCodes-DccrM4NI.d.ts → mobileErrorCodes-B3kTLit_.d.cts} +4 -2
  44. package/dist/mobileErrorCodes-B3kTLit_.d.cts.map +1 -0
  45. package/dist/{mobileErrorCodes-DccrM4NI.d.cts → mobileErrorCodes-B3kTLit_.d.ts} +4 -2
  46. package/dist/mobileErrorCodes-B3kTLit_.d.ts.map +1 -0
  47. package/dist/{payloadHash-CSgTglN4.d.cts → payloadHash-Brc5ceFq.d.cts} +2 -2
  48. package/dist/payloadHash-Brc5ceFq.d.cts.map +1 -0
  49. package/dist/{payloadHash-qsU1DEF0.d.ts → payloadHash-cZgv7NSo.d.ts} +2 -2
  50. package/dist/payloadHash-cZgv7NSo.d.ts.map +1 -0
  51. package/dist/profile-BozA3yVP.d.cts +16 -0
  52. package/dist/profile-BozA3yVP.d.cts.map +1 -0
  53. package/dist/profile-BozA3yVP.d.ts +16 -0
  54. package/dist/profile-BozA3yVP.d.ts.map +1 -0
  55. package/dist/{serverBaseTypes-DKCLDn3x.d.ts → serverBaseTypes-CWBdZomv.d.ts} +2 -2
  56. package/dist/{serverBaseTypes-DKCLDn3x.d.ts.map → serverBaseTypes-CWBdZomv.d.ts.map} +1 -1
  57. package/dist/{serverBaseTypes-CuMsGXgc.d.cts → serverBaseTypes-CcWT_ZBe.d.cts} +2 -2
  58. package/dist/{serverBaseTypes-CuMsGXgc.d.cts.map → serverBaseTypes-CcWT_ZBe.d.cts.map} +1 -1
  59. package/dist/{serverExecuteTypes-TPX0GCgv.d.cts → serverExecuteTypes-CgjzwBaA.d.cts} +24 -5
  60. package/dist/serverExecuteTypes-CgjzwBaA.d.cts.map +1 -0
  61. package/dist/{serverExecuteTypes-DKG1mqy1.d.ts → serverExecuteTypes-jyr5aO5q.d.ts} +24 -5
  62. package/dist/serverExecuteTypes-jyr5aO5q.d.ts.map +1 -0
  63. package/dist/{serverModelTypes-MlqdaMRd.d.ts → serverModelTypes-DAqEyYtB.d.cts} +25 -7
  64. package/dist/serverModelTypes-DAqEyYtB.d.cts.map +1 -0
  65. package/dist/{serverModelTypes-MlqdaMRd.d.cts → serverModelTypes-DAqEyYtB.d.ts} +25 -7
  66. package/dist/serverModelTypes-DAqEyYtB.d.ts.map +1 -0
  67. package/dist/{serverQueryTypes-BLUe10AI.d.ts → serverQueryTypes-DPRP61yA.d.ts} +14 -5
  68. package/dist/serverQueryTypes-DPRP61yA.d.ts.map +1 -0
  69. package/dist/{serverQueryTypes-BZOoJBpb.d.cts → serverQueryTypes-H_mI6fPl.d.cts} +14 -5
  70. package/dist/serverQueryTypes-H_mI6fPl.d.cts.map +1 -0
  71. package/dist/{serverRequestTypes-BULjZnnz.d.ts → serverRequestTypes-BY0f5woc.d.ts} +5 -3
  72. package/dist/serverRequestTypes-BY0f5woc.d.ts.map +1 -0
  73. package/dist/{serverRequestTypes-XbnLUsXT.d.cts → serverRequestTypes-DGGqQMK3.d.cts} +5 -3
  74. package/dist/serverRequestTypes-DGGqQMK3.d.cts.map +1 -0
  75. package/dist/{serverResponseGuards-DY_8lAo7.d.ts → serverResponseGuards-BGHTBbtz.d.ts} +2 -2
  76. package/dist/{serverResponseGuards-DY_8lAo7.d.ts.map → serverResponseGuards-BGHTBbtz.d.ts.map} +1 -1
  77. package/dist/{serverResponseGuards-DIj9MIrJ.d.cts → serverResponseGuards-DGhrUL_c.d.cts} +2 -2
  78. package/dist/{serverResponseGuards-DIj9MIrJ.d.cts.map → serverResponseGuards-DGhrUL_c.d.cts.map} +1 -1
  79. package/dist/signing/buildSignedMobileRequest.d.cts +1 -1
  80. package/dist/signing/buildSignedMobileRequest.d.ts +1 -1
  81. package/dist/signing/canonicalize.cjs +25 -0
  82. package/dist/signing/canonicalize.cjs.map +1 -1
  83. package/dist/signing/canonicalize.d.cts +1 -1
  84. package/dist/signing/canonicalize.d.ts +1 -1
  85. package/dist/signing/canonicalize.js +25 -0
  86. package/dist/signing/canonicalize.js.map +1 -1
  87. package/dist/signing/eip712MethodByType.cjs +3 -0
  88. package/dist/signing/eip712MethodByType.cjs.map +1 -1
  89. package/dist/signing/eip712MethodByType.d.cts +1 -1
  90. package/dist/signing/eip712MethodByType.d.ts +1 -1
  91. package/dist/signing/eip712MethodByType.js +3 -0
  92. package/dist/signing/eip712MethodByType.js.map +1 -1
  93. package/dist/signing/index.d.cts +5 -5
  94. package/dist/signing/index.d.ts +5 -5
  95. package/dist/signing/payloadHash.d.cts +1 -1
  96. package/dist/signing/payloadHash.d.ts +1 -1
  97. package/dist/signing/types.d.cts +1 -1
  98. package/dist/signing/types.d.ts +1 -1
  99. package/dist/types/MobileServerFailureError.d.cts +1 -1
  100. package/dist/types/MobileServerFailureError.d.ts +1 -1
  101. package/dist/types/clientTypes.d.cts +2 -2
  102. package/dist/types/clientTypes.d.ts +2 -2
  103. package/dist/types/index.d.cts +9 -9
  104. package/dist/types/index.d.ts +9 -9
  105. package/dist/types/mobileErrorCodes.cjs +4 -0
  106. package/dist/types/mobileErrorCodes.cjs.map +1 -1
  107. package/dist/types/mobileErrorCodes.d.cts +1 -1
  108. package/dist/types/mobileErrorCodes.d.ts +1 -1
  109. package/dist/types/mobileErrorCodes.js +4 -0
  110. package/dist/types/mobileErrorCodes.js.map +1 -1
  111. package/dist/types/serverBaseTypes.d.cts +1 -1
  112. package/dist/types/serverBaseTypes.d.ts +1 -1
  113. package/dist/types/serverExecuteTypes.d.cts +2 -2
  114. package/dist/types/serverExecuteTypes.d.ts +2 -2
  115. package/dist/types/serverModelTypes.cjs.map +1 -1
  116. package/dist/types/serverModelTypes.d.cts +2 -2
  117. package/dist/types/serverModelTypes.d.ts +2 -2
  118. package/dist/types/serverModelTypes.js.map +1 -1
  119. package/dist/types/serverQueryTypes.d.cts +2 -2
  120. package/dist/types/serverQueryTypes.d.ts +2 -2
  121. package/dist/types/serverRequestTypes.d.cts +1 -1
  122. package/dist/types/serverRequestTypes.d.ts +1 -1
  123. package/dist/{types-B_4veFLc.d.ts → types-B021odcS.d.ts} +12 -3
  124. package/dist/types-B021odcS.d.ts.map +1 -0
  125. package/dist/{types-CwpXP7xM.d.cts → types-l47aSWtA.d.cts} +12 -3
  126. package/dist/types-l47aSWtA.d.cts.map +1 -0
  127. package/dist/utils/index.cjs +4 -0
  128. package/dist/utils/index.d.cts +3 -2
  129. package/dist/utils/index.d.ts +3 -2
  130. package/dist/utils/index.js +2 -1
  131. package/dist/utils/profile.cjs +22 -0
  132. package/dist/utils/profile.cjs.map +1 -0
  133. package/dist/utils/profile.d.cts +2 -0
  134. package/dist/utils/profile.d.ts +2 -0
  135. package/dist/utils/profile.js +19 -0
  136. package/dist/utils/profile.js.map +1 -0
  137. package/dist/utils/serverResponseGuards.d.cts +1 -1
  138. package/dist/utils/serverResponseGuards.d.ts +1 -1
  139. package/package.json +3 -3
  140. package/src/MobileClient.ts +85 -3
  141. package/src/dataMappers.ts +49 -4
  142. package/src/signing/canonicalize.ts +20 -0
  143. package/src/signing/eip712MethodByType.ts +3 -0
  144. package/src/signing/signing.test.ts +67 -1
  145. package/src/signing/types.ts +10 -1
  146. package/src/types/clientTypes.ts +73 -9
  147. package/src/types/mobileErrorCodes.ts +4 -0
  148. package/src/types/serverExecuteTypes.ts +21 -1
  149. package/src/types/serverModelTypes.ts +31 -5
  150. package/src/types/serverQueryTypes.ts +11 -0
  151. package/src/types/serverRequestTypes.ts +2 -0
  152. package/src/utils/index.ts +1 -0
  153. package/src/utils/profile.test.ts +22 -0
  154. package/src/utils/profile.ts +16 -0
  155. package/dist/MobileClient-BbTaqTzi.cjs.map +0 -1
  156. package/dist/canonicalize-0_B6UOxO.d.cts.map +0 -1
  157. package/dist/canonicalize-BC-JICjp.d.ts.map +0 -1
  158. package/dist/clientTypes-P4LAjreY.d.ts.map +0 -1
  159. package/dist/clientTypes-YF5d8bvg.d.cts.map +0 -1
  160. package/dist/eip712MethodByType-DWtLyPY7.d.ts.map +0 -1
  161. package/dist/eip712MethodByType-sHQ-VTHd.d.cts.map +0 -1
  162. package/dist/mobileErrorCodes-DccrM4NI.d.cts.map +0 -1
  163. package/dist/mobileErrorCodes-DccrM4NI.d.ts.map +0 -1
  164. package/dist/payloadHash-CSgTglN4.d.cts.map +0 -1
  165. package/dist/payloadHash-qsU1DEF0.d.ts.map +0 -1
  166. package/dist/serverExecuteTypes-DKG1mqy1.d.ts.map +0 -1
  167. package/dist/serverExecuteTypes-TPX0GCgv.d.cts.map +0 -1
  168. package/dist/serverModelTypes-MlqdaMRd.d.cts.map +0 -1
  169. package/dist/serverModelTypes-MlqdaMRd.d.ts.map +0 -1
  170. package/dist/serverQueryTypes-BLUe10AI.d.ts.map +0 -1
  171. package/dist/serverQueryTypes-BZOoJBpb.d.cts.map +0 -1
  172. package/dist/serverRequestTypes-BULjZnnz.d.ts.map +0 -1
  173. package/dist/serverRequestTypes-XbnLUsXT.d.cts.map +0 -1
  174. package/dist/types-B_4veFLc.d.ts.map +0 -1
  175. package/dist/types-CwpXP7xM.d.cts.map +0 -1
@@ -1,5 +1,5 @@
1
- import { l as MobileNotificationPlatform } from "./serverModelTypes-MlqdaMRd.js";
2
- import { F as MobileSignedRequestParams } from "./clientTypes-P4LAjreY.js";
1
+ import { d as MobileServerAvatarSelection, l as MobileNotificationPlatform } from "./serverModelTypes-DAqEyYtB.js";
2
+ import { V as MobileSignedRequestParams } from "./clientTypes-ws9CDHw4.js";
3
3
  import { WalletClientWithAccount } from "@nadohq/shared";
4
4
  import { Hex } from "viem";
5
5
 
@@ -19,6 +19,15 @@ import { Hex } from "viem";
19
19
  * lowercases; unlike bytes32, string fields such as `display_name` are hashed as-is and keep their casing.
20
20
  */
21
21
  type MobileSignedInner = {
22
+ type: 'set_bio';
23
+ bio: string;
24
+ } | {
25
+ type: 'create_avatar_upload';
26
+ content_length: number;
27
+ } | {
28
+ type: 'set_avatar';
29
+ avatar: MobileServerAvatarSelection | null;
30
+ } | {
22
31
  type: 'set_username';
23
32
  display_name: string;
24
33
  } | {
@@ -68,4 +77,4 @@ interface BuildSignedMobileRequestParams extends MobileSignedRequestParams {
68
77
  }
69
78
  //#endregion
70
79
  export { MobileSignedRequest as a, MobileSignedInnerParams as i, MobileSignedInner as n, MobileSignedInnerByType as r, BuildSignedMobileRequestParams as t };
71
- //# sourceMappingURL=types-B_4veFLc.d.ts.map
80
+ //# sourceMappingURL=types-B021odcS.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-B021odcS.d.ts","names":[],"sources":["../src/signing/src/signing/types.ts"],"mappings":";;;;;;;;AAsBA;;;;;;;;;;;;KAAY,iBAAA;EACN,IAAA;EAAiB,GAAA;AAAA;EACjB,IAAA;EAA8B,cAAA;AAAA;EAE9B,IAAA;EACA,MAAA,EAAQ,2BAAA;AAAA;EAER,IAAA;EAAsB,YAAA;AAAA;EACtB,IAAA;EAA0B,YAAA;AAAA;EAE1B,IAAA;EACA,UAAA;EACA,QAAA,EAAU,0BAAA;EAGV,MAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,UAAA,EAAY,GAAA,EASmB;EAP/B,YAAA;AAAA;;;;KAMM,uBAAA,WAAkC,iBAAA,YAC5C,OAAA,CAAQ,iBAAA;EAAqB,IAAA,EAAM,CAAA;AAAA;;;AAAC;AAMtC;KAAY,uBAAA,WAAkC,iBAAA,YAA6B,IAAA,CACzE,uBAAA,CAAwB,CAAA;;;;;KAQd,mBAAA,WACA,iBAAA,GAAoB,iBAAA,IAC5B,CAAA;EACF,SAAA,EAAW,GAAA;EACX,MAAA,EAAQ,GAAA;EACR,KAAA;AAAA;;;;UAMe,8BAAA,SAAuC,yBAAA;EACtD,YAAA,EAAc,uBAAA;EACd,KAAA,EAAO,iBAAA;EAbsB;;;EAiB7B,KAAA;AAAA"}
@@ -1,5 +1,5 @@
1
- import { l as MobileNotificationPlatform } from "./serverModelTypes-MlqdaMRd.cjs";
2
- import { F as MobileSignedRequestParams } from "./clientTypes-YF5d8bvg.cjs";
1
+ import { d as MobileServerAvatarSelection, l as MobileNotificationPlatform } from "./serverModelTypes-DAqEyYtB.cjs";
2
+ import { V as MobileSignedRequestParams } from "./clientTypes-DnPE1zZO.cjs";
3
3
  import { WalletClientWithAccount } from "@nadohq/shared";
4
4
  import { Hex } from "viem";
5
5
 
@@ -19,6 +19,15 @@ import { Hex } from "viem";
19
19
  * lowercases; unlike bytes32, string fields such as `display_name` are hashed as-is and keep their casing.
20
20
  */
21
21
  type MobileSignedInner = {
22
+ type: 'set_bio';
23
+ bio: string;
24
+ } | {
25
+ type: 'create_avatar_upload';
26
+ content_length: number;
27
+ } | {
28
+ type: 'set_avatar';
29
+ avatar: MobileServerAvatarSelection | null;
30
+ } | {
22
31
  type: 'set_username';
23
32
  display_name: string;
24
33
  } | {
@@ -68,4 +77,4 @@ interface BuildSignedMobileRequestParams extends MobileSignedRequestParams {
68
77
  }
69
78
  //#endregion
70
79
  export { MobileSignedRequest as a, MobileSignedInnerParams as i, MobileSignedInner as n, MobileSignedInnerByType as r, BuildSignedMobileRequestParams as t };
71
- //# sourceMappingURL=types-CwpXP7xM.d.cts.map
80
+ //# sourceMappingURL=types-l47aSWtA.d.cts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types-l47aSWtA.d.cts","names":[],"sources":["../src/signing/src/signing/types.ts"],"mappings":";;;;;;;;AAsBA;;;;;;;;;;;;KAAY,iBAAA;EACN,IAAA;EAAiB,GAAA;AAAA;EACjB,IAAA;EAA8B,cAAA;AAAA;EAE9B,IAAA;EACA,MAAA,EAAQ,2BAAA;AAAA;EAER,IAAA;EAAsB,YAAA;AAAA;EACtB,IAAA;EAA0B,YAAA;AAAA;EAE1B,IAAA;EACA,UAAA;EACA,QAAA,EAAU,0BAAA;EAGV,MAAA;EACA,WAAA;AAAA;EAGA,IAAA;EACA,UAAA,EAAY,GAAA,EASmB;EAP/B,YAAA;AAAA;;;;KAMM,uBAAA,WAAkC,iBAAA,YAC5C,OAAA,CAAQ,iBAAA;EAAqB,IAAA,EAAM,CAAA;AAAA;;;AAAC;AAMtC;KAAY,uBAAA,WAAkC,iBAAA,YAA6B,IAAA,CACzE,uBAAA,CAAwB,CAAA;;;;;KAQd,mBAAA,WACA,iBAAA,GAAoB,iBAAA,IAC5B,CAAA;EACF,SAAA,EAAW,GAAA;EACX,MAAA,EAAQ,GAAA;EACR,KAAA;AAAA;;;;UAMe,8BAAA,SAAuC,yBAAA;EACtD,YAAA,EAAc,uBAAA;EACd,KAAA,EAAO,iBAAA;EAbsB;;;EAiB7B,KAAA;AAAA"}
@@ -3,6 +3,9 @@ const require_utils_serverResponseGuards = require("./serverResponseGuards.cjs")
3
3
  const require_utils_feed = require("./feed.cjs");
4
4
  const require_utils_follow = require("./follow.cjs");
5
5
  const require_utils_patterns = require("./patterns.cjs");
6
+ const require_utils_profile = require("./profile.cjs");
7
+ exports.MOBILE_AVATAR_MAX_UPLOAD_BYTES = require_utils_profile.MOBILE_AVATAR_MAX_UPLOAD_BYTES;
8
+ exports.MOBILE_BIO_MAX_LENGTH = require_utils_profile.MOBILE_BIO_MAX_LENGTH;
6
9
  exports.MOBILE_DISPLAY_NAME_PATTERN = require_utils_patterns.MOBILE_DISPLAY_NAME_PATTERN;
7
10
  exports.MOBILE_FEED_MAX_PAGE_SIZE = require_utils_feed.MOBILE_FEED_MAX_PAGE_SIZE;
8
11
  exports.MOBILE_FEED_MIN_NOTIONAL_FLOOR = require_utils_feed.MOBILE_FEED_MIN_NOTIONAL_FLOOR;
@@ -12,3 +15,4 @@ exports.MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE = require_utils_follow.MOBILE_FOLLOW_LI
12
15
  exports.MOBILE_PROFILES_MAX_BATCH_SIZE = require_utils_follow.MOBILE_PROFILES_MAX_BATCH_SIZE;
13
16
  exports.isMobileServerFailureResponse = require_utils_serverResponseGuards.isMobileServerFailureResponse;
14
17
  exports.isMobileServerSuccessResponse = require_utils_serverResponseGuards.isMobileServerSuccessResponse;
18
+ exports.isValidMobileBio = require_utils_profile.isValidMobileBio;
@@ -1,5 +1,6 @@
1
1
  import { n as MOBILE_FEED_MIN_NOTIONAL_FLOOR, t as MOBILE_FEED_MAX_PAGE_SIZE } from "../feed-DTJlsg8W.cjs";
2
2
  import { i as MOBILE_PROFILES_MAX_BATCH_SIZE, n as MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, r as MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, t as MOBILE_FOLLOWED_BY_PREVIEW_LIMIT } from "../follow-D6Mg8GHx.cjs";
3
3
  import { t as MOBILE_DISPLAY_NAME_PATTERN } from "../patterns-BE0Audp5.cjs";
4
- import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-DIj9MIrJ.cjs";
5
- export { MOBILE_DISPLAY_NAME_PATTERN, MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR, MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE, isMobileServerFailureResponse, isMobileServerSuccessResponse };
4
+ import { n as MOBILE_BIO_MAX_LENGTH, r as isValidMobileBio, t as MOBILE_AVATAR_MAX_UPLOAD_BYTES } from "../profile-BozA3yVP.cjs";
5
+ import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-DGhrUL_c.cjs";
6
+ export { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, MOBILE_DISPLAY_NAME_PATTERN, MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR, MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE, isMobileServerFailureResponse, isMobileServerSuccessResponse, isValidMobileBio };
@@ -1,5 +1,6 @@
1
1
  import { n as MOBILE_FEED_MIN_NOTIONAL_FLOOR, t as MOBILE_FEED_MAX_PAGE_SIZE } from "../feed-DTJlsg8W.js";
2
2
  import { i as MOBILE_PROFILES_MAX_BATCH_SIZE, n as MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, r as MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, t as MOBILE_FOLLOWED_BY_PREVIEW_LIMIT } from "../follow-D6Mg8GHx.js";
3
3
  import { t as MOBILE_DISPLAY_NAME_PATTERN } from "../patterns-BE0Audp5.js";
4
- import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-DY_8lAo7.js";
5
- export { MOBILE_DISPLAY_NAME_PATTERN, MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR, MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE, isMobileServerFailureResponse, isMobileServerSuccessResponse };
4
+ import { n as MOBILE_BIO_MAX_LENGTH, r as isValidMobileBio, t as MOBILE_AVATAR_MAX_UPLOAD_BYTES } from "../profile-BozA3yVP.js";
5
+ import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-BGHTBbtz.js";
6
+ export { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, MOBILE_DISPLAY_NAME_PATTERN, MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR, MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE, isMobileServerFailureResponse, isMobileServerSuccessResponse, isValidMobileBio };
@@ -2,4 +2,5 @@ import { isMobileServerFailureResponse, isMobileServerSuccessResponse } from "./
2
2
  import { MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR } from "./feed.js";
3
3
  import { MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE } from "./follow.js";
4
4
  import { MOBILE_DISPLAY_NAME_PATTERN } from "./patterns.js";
5
- export { MOBILE_DISPLAY_NAME_PATTERN, MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR, MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE, isMobileServerFailureResponse, isMobileServerSuccessResponse };
5
+ import { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, isValidMobileBio } from "./profile.js";
6
+ export { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, MOBILE_DISPLAY_NAME_PATTERN, MOBILE_FEED_MAX_PAGE_SIZE, MOBILE_FEED_MIN_NOTIONAL_FLOOR, MOBILE_FOLLOWED_BY_PREVIEW_LIMIT, MOBILE_FOLLOW_LIST_DEFAULT_PAGE_SIZE, MOBILE_FOLLOW_LIST_MAX_PAGE_SIZE, MOBILE_PROFILES_MAX_BATCH_SIZE, isMobileServerFailureResponse, isMobileServerSuccessResponse, isValidMobileBio };
@@ -0,0 +1,22 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ //#region src/utils/profile.ts
3
+ /**
4
+ * Maximum biography length in Unicode code points. Exceeding it fails with `INVALID_BIO`.
5
+ */
6
+ const MOBILE_BIO_MAX_LENGTH = 150;
7
+ /**
8
+ * Maximum JPEG or PNG upload size in bytes. Exceeding it fails with `INVALID_AVATAR`.
9
+ */
10
+ const MOBILE_AVATAR_MAX_UPLOAD_BYTES = 5 * 1024 * 1024;
11
+ /**
12
+ * Checks biography protocol limits; whitespace-only text is valid and clears the bio.
13
+ */
14
+ function isValidMobileBio(bio) {
15
+ return !bio.includes("\0") && Array.from(bio).length <= 150;
16
+ }
17
+ //#endregion
18
+ exports.MOBILE_AVATAR_MAX_UPLOAD_BYTES = MOBILE_AVATAR_MAX_UPLOAD_BYTES;
19
+ exports.MOBILE_BIO_MAX_LENGTH = MOBILE_BIO_MAX_LENGTH;
20
+ exports.isValidMobileBio = isValidMobileBio;
21
+
22
+ //# sourceMappingURL=profile.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.cjs","names":[],"sources":["../../src/utils/profile.ts"],"sourcesContent":["/**\n * Maximum biography length in Unicode code points. Exceeding it fails with `INVALID_BIO`.\n */\nexport const MOBILE_BIO_MAX_LENGTH = 150;\n\n/**\n * Maximum JPEG or PNG upload size in bytes. Exceeding it fails with `INVALID_AVATAR`.\n */\nexport const MOBILE_AVATAR_MAX_UPLOAD_BYTES = 5 * 1024 * 1024;\n\n/**\n * Checks biography protocol limits; whitespace-only text is valid and clears the bio.\n */\nexport function isValidMobileBio(bio: string): boolean {\n return !bio.includes('\\0') && Array.from(bio).length <= MOBILE_BIO_MAX_LENGTH;\n}\n"],"mappings":";;;;;AAGA,MAAa,wBAAwB;;;;AAKrC,MAAa,iCAAiC,IAAI,OAAO;;;;AAKzD,SAAgB,iBAAiB,KAAsB;CACrD,OAAO,CAAC,IAAI,SAAS,IAAI,KAAK,MAAM,KAAK,GAAG,EAAE,UAAA;AAChD"}
@@ -0,0 +1,2 @@
1
+ import { n as MOBILE_BIO_MAX_LENGTH, r as isValidMobileBio, t as MOBILE_AVATAR_MAX_UPLOAD_BYTES } from "../profile-BozA3yVP.cjs";
2
+ export { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, isValidMobileBio };
@@ -0,0 +1,2 @@
1
+ import { n as MOBILE_BIO_MAX_LENGTH, r as isValidMobileBio, t as MOBILE_AVATAR_MAX_UPLOAD_BYTES } from "../profile-BozA3yVP.js";
2
+ export { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, isValidMobileBio };
@@ -0,0 +1,19 @@
1
+ //#region src/utils/profile.ts
2
+ /**
3
+ * Maximum biography length in Unicode code points. Exceeding it fails with `INVALID_BIO`.
4
+ */
5
+ const MOBILE_BIO_MAX_LENGTH = 150;
6
+ /**
7
+ * Maximum JPEG or PNG upload size in bytes. Exceeding it fails with `INVALID_AVATAR`.
8
+ */
9
+ const MOBILE_AVATAR_MAX_UPLOAD_BYTES = 5 * 1024 * 1024;
10
+ /**
11
+ * Checks biography protocol limits; whitespace-only text is valid and clears the bio.
12
+ */
13
+ function isValidMobileBio(bio) {
14
+ return !bio.includes("\0") && Array.from(bio).length <= 150;
15
+ }
16
+ //#endregion
17
+ export { MOBILE_AVATAR_MAX_UPLOAD_BYTES, MOBILE_BIO_MAX_LENGTH, isValidMobileBio };
18
+
19
+ //# sourceMappingURL=profile.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"profile.js","names":[],"sources":["../../src/utils/profile.ts"],"sourcesContent":["/**\n * Maximum biography length in Unicode code points. Exceeding it fails with `INVALID_BIO`.\n */\nexport const MOBILE_BIO_MAX_LENGTH = 150;\n\n/**\n * Maximum JPEG or PNG upload size in bytes. Exceeding it fails with `INVALID_AVATAR`.\n */\nexport const MOBILE_AVATAR_MAX_UPLOAD_BYTES = 5 * 1024 * 1024;\n\n/**\n * Checks biography protocol limits; whitespace-only text is valid and clears the bio.\n */\nexport function isValidMobileBio(bio: string): boolean {\n return !bio.includes('\\0') && Array.from(bio).length <= MOBILE_BIO_MAX_LENGTH;\n}\n"],"mappings":";;;;AAGA,MAAa,wBAAwB;;;;AAKrC,MAAa,iCAAiC,IAAI,OAAO;;;;AAKzD,SAAgB,iBAAiB,KAAsB;CACrD,OAAO,CAAC,IAAI,SAAS,IAAI,KAAK,MAAM,KAAK,GAAG,EAAE,UAAA;AAChD"}
@@ -1,2 +1,2 @@
1
- import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-DIj9MIrJ.cjs";
1
+ import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-DGhrUL_c.cjs";
2
2
  export { isMobileServerFailureResponse, isMobileServerSuccessResponse };
@@ -1,2 +1,2 @@
1
- import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-DY_8lAo7.js";
1
+ import { n as isMobileServerSuccessResponse, t as isMobileServerFailureResponse } from "../serverResponseGuards-BGHTBbtz.js";
2
2
  export { isMobileServerFailureResponse, isMobileServerSuccessResponse };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nadohq/mobile-client",
3
- "version": "0.54.0",
3
+ "version": "0.56.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "description": "HTTP client for the Nado mobile service API — username claims, profiles, privacy settings, and push notification devices & preferences",
@@ -42,7 +42,7 @@
42
42
  "types": "./dist/index.d.ts",
43
43
  "dependencies": {
44
44
  "@msgpack/msgpack": "3.1.3",
45
- "@nadohq/shared": "^0.54.0",
45
+ "@nadohq/shared": "^0.56.0",
46
46
  "axios": "1.16.1"
47
47
  },
48
48
  "peerDependencies": {
@@ -54,5 +54,5 @@
54
54
  "bignumber.js": "11.1.1",
55
55
  "viem": "2.52.0"
56
56
  },
57
- "gitHead": "83485ee66ad20b239387e271a2945386b39e824e"
57
+ "gitHead": "1b86723bc243f149ddf9e0d70a6be6d4bf3960a3"
58
58
  }
@@ -6,6 +6,9 @@ import {
6
6
  } from '@nadohq/shared';
7
7
  import axios, { AxiosInstance, AxiosResponse } from 'axios';
8
8
  import {
9
+ mapMobileAvatarPreset,
10
+ mapMobileAvatarSelectionToServer,
11
+ mapMobileAvatarUpload,
9
12
  mapMobileFeedPage,
10
13
  mapMobileFollowListPage,
11
14
  mapMobileFollowListParamsToServer,
@@ -46,6 +49,9 @@ import {
46
49
  GetMobileRegisteredWalletParams,
47
50
  GetMobileTopTradersFeedParams,
48
51
  GetMobileUsernameAvailabilityParams,
52
+ MobileAvatarPreset,
53
+ MobileAvatarUpload,
54
+ MobileCreateAvatarUploadParams,
49
55
  MobileFeedPage,
50
56
  MobileFollowListPage,
51
57
  MobileFollowMutationResult,
@@ -53,6 +59,8 @@ import {
53
59
  MobilePublicProfile,
54
60
  MobileRegisteredWallet,
55
61
  MobileRegisterExpoTokenParams,
62
+ MobileSetAvatarParams,
63
+ MobileSetBioParams,
56
64
  MobileSetFollowParams,
57
65
  MobileSetPrivateModeParams,
58
66
  MobileSetUsernameParams,
@@ -110,9 +118,9 @@ export interface MobileClientOpts {
110
118
  }
111
119
 
112
120
  /**
113
- * Client for the Nado mobile service API: usernames, public profile lookups, the global trade feed,
114
- * session-based social feeds, the follower/following graph, privacy settings, and push notification
115
- * device/preference management.
121
+ * Client for the Nado mobile service API: usernames, bios, avatars, public profile lookups, the global
122
+ * trade feed, session-based social feeds, the follower/following graph, privacy settings, and push
123
+ * notification device/preference management.
116
124
  */
117
125
  export class MobileClient {
118
126
  readonly opts: MobileClientOpts;
@@ -143,6 +151,19 @@ export class MobileClient {
143
151
  Public queries
144
152
  */
145
153
 
154
+ /**
155
+ * Returns the current server-owned avatar catalogue in display order.
156
+ *
157
+ * @throws {MobileServerFailureError} With `SERVICE_UNAVAILABLE` when avatar storage is not configured.
158
+ */
159
+ async getAvatarPresets(): Promise<MobileAvatarPreset[]> {
160
+ const body: MobileServerPublicQueryRequest<'avatar_presets'> = {
161
+ type: 'avatar_presets',
162
+ };
163
+ const data = await this.publicQuery(body);
164
+ return data.presets.map(mapMobileAvatarPreset);
165
+ }
166
+
146
167
  /**
147
168
  * Checks whether a username derived from the given display name is available to claim.
148
169
  */
@@ -510,10 +531,70 @@ export class MobileClient {
510
531
  Signed executes
511
532
  */
512
533
 
534
+ /**
535
+ * Updates the biography, or clears it when the text is whitespace-only.
536
+ *
537
+ * Serialize this with {@link MobileClient.setAvatar}, {@link MobileClient.setUsername} and
538
+ * {@link MobileClient.setPrivateMode} for the same subaccount: all share the identity update nonce.
539
+ *
540
+ * @throws {MobileServerFailureError} With `INVALID_BIO` for exceeding `MOBILE_BIO_MAX_LENGTH` or null
541
+ * characters, `INVALID_IDENTITY_TARGET` for an isolated subaccount, or `STALE_IDENTITY_UPDATE` when a
542
+ * later write has committed (re-read the profile before retrying).
543
+ */
544
+ async setBio(
545
+ params: MobileSetBioParams,
546
+ ): Promise<MobileServerSuccessResponse> {
547
+ const signedRequest = await this.getSignedRequest('set_bio', params, {
548
+ bio: params.bio,
549
+ });
550
+ return this.execute(signedRequest);
551
+ }
552
+
553
+ /**
554
+ * Creates a short-lived upload grant. The caller uploads an image meeting {@link MobileAvatarUpload}'s requirements;
555
+ * file access and transport remain platform-specific. This does not change the saved avatar.
556
+ *
557
+ * @throws {MobileServerFailureError} With `INVALID_AVATAR` for a zero or oversized upload,
558
+ * `INVALID_IDENTITY_TARGET` for an isolated subaccount, or `SERVICE_UNAVAILABLE` when storage is unavailable.
559
+ */
560
+ async createAvatarUpload(
561
+ params: MobileCreateAvatarUploadParams,
562
+ ): Promise<MobileAvatarUpload> {
563
+ const signedRequest = await this.getSignedRequest(
564
+ 'create_avatar_upload',
565
+ params,
566
+ { content_length: params.contentLength },
567
+ );
568
+ const data = await this.execute(signedRequest);
569
+ return mapMobileAvatarUpload(data);
570
+ }
571
+
572
+ /**
573
+ * Publishes a preset/staged upload, or clears the saved avatar when avatar is null.
574
+ * Uploaded JPEG/PNG images must be square, at most 4096 × 4096 pixels, and within
575
+ * `MOBILE_AVATAR_MAX_UPLOAD_BYTES`. A successful PUT can still fail this publication check.
576
+ *
577
+ * Serialize identity writes for the same subaccount; see {@link MobileClient.setBio}.
578
+ *
579
+ * @throws {MobileServerFailureError} With `INVALID_AVATAR` for an invalid preset, staging key, or image,
580
+ * `INVALID_IDENTITY_TARGET` for an isolated subaccount, `SERVICE_UNAVAILABLE` when storage is unavailable,
581
+ * or `STALE_IDENTITY_UPDATE` when a later write has committed (re-read the profile before retrying).
582
+ */
583
+ async setAvatar(
584
+ params: MobileSetAvatarParams,
585
+ ): Promise<MobileServerSuccessResponse> {
586
+ const signedRequest = await this.getSignedRequest('set_avatar', params, {
587
+ avatar: mapMobileAvatarSelectionToServer(params.avatar),
588
+ });
589
+ return this.execute(signedRequest);
590
+ }
591
+
513
592
  /**
514
593
  * Sets a subaccount's username, derived from the given display name. Upserts: the same call claims a first
515
594
  * username and renames an existing one, so callers never need to read the current identity first.
516
595
  *
596
+ * Serialize identity writes for the same subaccount; see {@link MobileClient.setBio}.
597
+ *
517
598
  * @throws {MobileServerFailureError} With error code `INVALID_DISPLAY_NAME` if the display name violates
518
599
  * `MOBILE_DISPLAY_NAME_PATTERN`, `USERNAME_UNAVAILABLE` if the derived username is reserved or already
519
600
  * taken by another subaccount, `INVALID_IDENTITY_TARGET` if the sender is in the engine-created isolated
@@ -531,6 +612,7 @@ export class MobileClient {
531
612
 
532
613
  /**
533
614
  * Sets whether a subaccount's profile is private.
615
+ * Serialize identity writes for the same subaccount; see {@link MobileClient.setBio}.
534
616
  */
535
617
  async setPrivateMode(
536
618
  params: MobileSetPrivateModeParams,
@@ -1,6 +1,9 @@
1
1
  import { removeDecimals, subaccountToHex, toBigNumber } from '@nadohq/shared';
2
2
  import {
3
3
  GetMobileFollowListParams,
4
+ MobileAvatarPreset,
5
+ MobileAvatarSelection,
6
+ MobileAvatarUpload,
4
7
  MobileFeedPage,
5
8
  MobileFeedTrade,
6
9
  MobileFollowListPage,
@@ -34,8 +37,13 @@ import {
34
37
  MobileSocialFeedTraderBadge,
35
38
  MobileSocialFeedUpdates,
36
39
  } from './types/clientTypes';
37
- import { MobileServerFollowMutationResponse } from './types/serverExecuteTypes';
38
40
  import {
41
+ MobileServerAvatarUploadResponse,
42
+ MobileServerFollowMutationResponse,
43
+ } from './types/serverExecuteTypes';
44
+ import {
45
+ MobileServerAvatarPreset,
46
+ MobileServerAvatarSelection,
39
47
  MobileServerFeedTrade,
40
48
  MobileServerFollowSummary,
41
49
  MobileServerIdentitySummary,
@@ -74,6 +82,44 @@ import {
74
82
  MobileServerSocialFeedReadParams,
75
83
  } from './types/serverRequestTypes';
76
84
 
85
+ /**
86
+ * Maps a server-side avatar preset to its client-side representation.
87
+ */
88
+ export function mapMobileAvatarPreset(
89
+ server: MobileServerAvatarPreset,
90
+ ): MobileAvatarPreset {
91
+ return { id: server.id, avatarUrl: server.avatar_url };
92
+ }
93
+
94
+ /**
95
+ * Maps an upload grant, preserving the signed PUT headers and server-provided lifetime.
96
+ */
97
+ export function mapMobileAvatarUpload(
98
+ server: MobileServerAvatarUploadResponse,
99
+ ): MobileAvatarUpload {
100
+ return {
101
+ uploadKey: server.upload_key,
102
+ uploadUrl: server.upload_url,
103
+ headers: server.headers,
104
+ expiresInSeconds: server.expires_in_seconds,
105
+ };
106
+ }
107
+
108
+ /**
109
+ * Maps a client-side avatar selection to the signed wire payload; null clears the saved avatar.
110
+ */
111
+ export function mapMobileAvatarSelectionToServer(
112
+ avatar: MobileAvatarSelection | null,
113
+ ): MobileServerAvatarSelection | null {
114
+ if (avatar === null) {
115
+ return null;
116
+ }
117
+ if (avatar.type === 'preset') {
118
+ return { type: 'preset', id: avatar.id };
119
+ }
120
+ return { type: 'upload', upload_key: avatar.uploadKey };
121
+ }
122
+
77
123
  /**
78
124
  * Maps a server-side public profile (snake_case) to its client-side (camelCase) representation. The three
79
125
  * include-gated fields stay `undefined` when the backend omitted them, rather than being coerced to `null`
@@ -83,9 +129,8 @@ export function mapMobilePublicProfile(
83
129
  server: MobileServerProfile,
84
130
  ): MobilePublicProfile {
85
131
  return {
86
- subaccount: server.subaccount,
87
- username: server.username,
88
- displayName: server.display_name,
132
+ ...mapMobileIdentitySummary(server),
133
+ bio: server.bio,
89
134
  privateMode: server.private_mode,
90
135
  followerCount: server.follower_count,
91
136
  followingCount: server.following_count,
@@ -11,6 +11,26 @@ export function canonicalizeMobileInner(
11
11
  inner: MobileSignedInner,
12
12
  ): MobileSignedInner {
13
13
  switch (inner.type) {
14
+ case 'set_bio':
15
+ return { type: 'set_bio', bio: inner.bio };
16
+ case 'create_avatar_upload':
17
+ return {
18
+ type: 'create_avatar_upload',
19
+ content_length: inner.content_length,
20
+ };
21
+ case 'set_avatar': {
22
+ const avatar = inner.avatar;
23
+ if (avatar === null) {
24
+ return { type: 'set_avatar', avatar: null };
25
+ }
26
+ return {
27
+ type: 'set_avatar',
28
+ avatar:
29
+ avatar.type === 'preset'
30
+ ? { type: 'preset', id: avatar.id }
31
+ : { type: 'upload', upload_key: avatar.upload_key },
32
+ };
33
+ }
14
34
  case 'set_username':
15
35
  return { type: 'set_username', display_name: inner.display_name };
16
36
  case 'set_private_mode':
@@ -7,6 +7,9 @@ export const MOBILE_EIP712_METHOD_BY_TYPE: Record<
7
7
  MobileSignedInner['type'],
8
8
  string
9
9
  > = {
10
+ set_bio: 'mobile:execute_set_bio',
11
+ create_avatar_upload: 'mobile:execute_create_avatar_upload',
12
+ set_avatar: 'mobile:execute_set_avatar',
10
13
  set_username: 'mobile:execute_set_username',
11
14
  set_private_mode: 'mobile:execute_set_private_mode',
12
15
  register_expo_token: 'mobile:execute_register_expo_token',
@@ -19,9 +19,18 @@ const FIXED_PRIVATE_KEY =
19
19
  '0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b786907' as const;
20
20
  const FIXED_VERIFYING_ADDR = '0x0000000000000000000000000000000000000001';
21
21
 
22
- // Every hash here mirrors the backend's pinned fixtures in mobile/src/api/types.rs, so a divergence is a
22
+ // Every hash here mirrors the backend's pinned fixtures in mobile/src/api, so a divergence is a
23
23
  // real wire-format break rather than a stale expectation.
24
24
  const PINNED_HASHES = {
25
+ set_bio: '0x96206cad01c9b00d69412721842ca0866bb1a82ec90f3979b8bcc91dc96a1243',
26
+ create_avatar_upload:
27
+ '0xb3811340e751e2799d3a24467fa50aeb221e1ecea5aa6599ab09bd2426162495',
28
+ set_avatar_preset:
29
+ '0x9113b26919a71b910a4f61f4342121896a106014acaeef5da5a2d2e3f09e17ab',
30
+ set_avatar_clear:
31
+ '0x8ed3e0bc36cda8de523a22414c495e12385366d1cb61622be807b939505174ae',
32
+ set_avatar_upload:
33
+ '0xe036ffdffa1fdde9104a1cee9bb254352de293550dade21e439a65fc6fbd3d2c',
25
34
  set_username:
26
35
  '0xb4a55d9eb0be4e5c9457761c0c34c75cf39f7c07bd170700d8dd5e9c7de4a659',
27
36
  set_private_mode:
@@ -40,6 +49,53 @@ const FIXTURE_TARGET_SUBACCOUNT =
40
49
 
41
50
  describe('[mobile-client]: signing (offline)', () => {
42
51
  describe('pinned payload hashes', () => {
52
+ it('set_bio', () => {
53
+ const inner: MobileSignedInner = {
54
+ type: 'set_bio',
55
+ bio: 'Trading 中文 🚀\nBuilding on @inkhq',
56
+ };
57
+ expect(getMobilePayloadHash(canonicalizeMobileInner(inner))).toBe(
58
+ PINNED_HASHES.set_bio,
59
+ );
60
+ });
61
+
62
+ it('create_avatar_upload', () => {
63
+ const inner: MobileSignedInner = {
64
+ type: 'create_avatar_upload',
65
+ content_length: 12345,
66
+ };
67
+ expect(getMobilePayloadHash(canonicalizeMobileInner(inner))).toBe(
68
+ PINNED_HASHES.create_avatar_upload,
69
+ );
70
+ });
71
+
72
+ it('set_avatar (preset)', () => {
73
+ const inner: MobileSignedInner = {
74
+ type: 'set_avatar',
75
+ avatar: { type: 'preset', id: 'penguin' },
76
+ };
77
+ expect(getMobilePayloadHash(canonicalizeMobileInner(inner))).toBe(
78
+ PINNED_HASHES.set_avatar_preset,
79
+ );
80
+ });
81
+
82
+ it('set_avatar (clear)', () => {
83
+ const inner: MobileSignedInner = { type: 'set_avatar', avatar: null };
84
+ expect(getMobilePayloadHash(canonicalizeMobileInner(inner))).toBe(
85
+ PINNED_HASHES.set_avatar_clear,
86
+ );
87
+ });
88
+
89
+ it('set_avatar (upload)', () => {
90
+ const inner: MobileSignedInner = {
91
+ type: 'set_avatar',
92
+ avatar: { type: 'upload', upload_key: 'staging/avatars/test' },
93
+ };
94
+ expect(getMobilePayloadHash(canonicalizeMobileInner(inner))).toBe(
95
+ PINNED_HASHES.set_avatar_upload,
96
+ );
97
+ });
98
+
43
99
  it('set_username', () => {
44
100
  const inner: MobileSignedInner = {
45
101
  type: 'set_username',
@@ -91,6 +147,16 @@ describe('[mobile-client]: signing (offline)', () => {
91
147
  });
92
148
  });
93
149
 
150
+ it('canonicalizes nested avatar fields before hashing', () => {
151
+ const inner: MobileSignedInner = {
152
+ avatar: { id: 'penguin', type: 'preset' },
153
+ type: 'set_avatar',
154
+ };
155
+ expect(getMobilePayloadHash(canonicalizeMobileInner(inner))).toBe(
156
+ PINNED_HASHES.set_avatar_preset,
157
+ );
158
+ });
159
+
94
160
  it('canonicalizes msgpack key order regardless of input key order', () => {
95
161
  // Deliberately construct the inner payload with `type` last — canonicalizeMobileInner must rebuild it
96
162
  // with `type` first so the msgpack encoding (and therefore the payload hash) is deterministic.
@@ -1,7 +1,10 @@
1
1
  import { WalletClientWithAccount } from '@nadohq/shared';
2
2
  import { Hex } from 'viem';
3
3
  import { MobileSignedRequestParams } from '../types/clientTypes';
4
- import { MobileNotificationPlatform } from '../types/serverModelTypes';
4
+ import {
5
+ MobileNotificationPlatform,
6
+ MobileServerAvatarSelection,
7
+ } from '../types/serverModelTypes';
5
8
 
6
9
  /**
7
10
  * Unsigned inner payloads that can be authenticated against the mobile service API.
@@ -18,6 +21,12 @@ import { MobileNotificationPlatform } from '../types/serverModelTypes';
18
21
  * lowercases; unlike bytes32, string fields such as `display_name` are hashed as-is and keep their casing.
19
22
  */
20
23
  export type MobileSignedInner =
24
+ | { type: 'set_bio'; bio: string }
25
+ | { type: 'create_avatar_upload'; content_length: number }
26
+ | {
27
+ type: 'set_avatar';
28
+ avatar: MobileServerAvatarSelection | null;
29
+ }
21
30
  | { type: 'set_username'; display_name: string }
22
31
  | { type: 'set_private_mode'; private_mode: boolean }
23
32
  | {