@nadohq/mobile-client 0.65.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +202 -10
- package/dist/{MobileClient-CfVZXTcz.cjs → MobileClient-vuI5wlB_.cjs} +303 -21
- package/dist/MobileClient-vuI5wlB_.cjs.map +1 -0
- package/dist/MobileClient.cjs +1 -1
- package/dist/MobileClient.d.cts +175 -20
- package/dist/MobileClient.d.cts.map +1 -1
- package/dist/MobileClient.d.ts +175 -20
- package/dist/MobileClient.d.ts.map +1 -1
- package/dist/MobileClient.js +303 -21
- package/dist/MobileClient.js.map +1 -1
- package/dist/{MobileServerFailureError-BZVwlsMg.d.ts → MobileServerFailureError-BeCCNShj.d.cts} +2 -3
- package/dist/MobileServerFailureError-BeCCNShj.d.cts.map +1 -0
- package/dist/{MobileServerFailureError-CbtK8kD4.d.cts → MobileServerFailureError-hHv28weI.d.ts} +2 -3
- package/dist/MobileServerFailureError-hHv28weI.d.ts.map +1 -0
- package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.cts +15 -0
- package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.cts.map +1 -0
- package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.ts +15 -0
- package/dist/MobileUnsupportedNotificationRouteError-DpiNBvvY.d.ts.map +1 -0
- package/dist/{buildSignedMobileRequest-C1v0flCR.d.cts → buildSignedMobileRequest-DcEMKU_4.d.cts} +2 -2
- package/dist/{buildSignedMobileRequest-C1v0flCR.d.cts.map → buildSignedMobileRequest-DcEMKU_4.d.cts.map} +1 -1
- package/dist/{buildSignedMobileRequest-UeeWdYGU.d.ts → buildSignedMobileRequest-DlTMvoXR.d.ts} +2 -2
- package/dist/{buildSignedMobileRequest-UeeWdYGU.d.ts.map → buildSignedMobileRequest-DlTMvoXR.d.ts.map} +1 -1
- package/dist/{canonicalize-5eeZrkzQ.d.ts → canonicalize-BOZlflI3.d.ts} +2 -2
- package/dist/canonicalize-BOZlflI3.d.ts.map +1 -0
- package/dist/{canonicalize-CBaZprTo.d.cts → canonicalize-BvCozzvJ.d.cts} +2 -2
- package/dist/canonicalize-BvCozzvJ.d.cts.map +1 -0
- package/dist/{clientTypes-_mEgzmNs.d.cts → clientTypes-KpHlCDGZ.d.cts} +341 -38
- package/dist/clientTypes-KpHlCDGZ.d.cts.map +1 -0
- package/dist/{clientTypes-C9dJufxk.d.ts → clientTypes-XRI41VdC.d.ts} +341 -38
- package/dist/clientTypes-XRI41VdC.d.ts.map +1 -0
- package/dist/dataMappers.cjs +257 -20
- package/dist/dataMappers.cjs.map +1 -1
- package/dist/dataMappers.d.cts +98 -15
- package/dist/dataMappers.d.cts.map +1 -1
- package/dist/dataMappers.d.ts +98 -15
- package/dist/dataMappers.d.ts.map +1 -1
- package/dist/dataMappers.js +242 -20
- package/dist/dataMappers.js.map +1 -1
- package/dist/{eip712MethodByType-D8jLoxDu.d.cts → eip712MethodByType-DyAmzH7b.d.cts} +2 -2
- package/dist/eip712MethodByType-DyAmzH7b.d.cts.map +1 -0
- package/dist/{eip712MethodByType-DcUh8h-l.d.ts → eip712MethodByType-qSSAF6i2.d.ts} +2 -2
- package/dist/eip712MethodByType-qSSAF6i2.d.ts.map +1 -0
- package/dist/feed-BrgkFqP3.d.cts +23 -0
- package/dist/feed-BrgkFqP3.d.cts.map +1 -0
- package/dist/feed-DcbhLoo1.d.ts +23 -0
- package/dist/feed-DcbhLoo1.d.ts.map +1 -0
- package/dist/index-BVVgDSdq.d.cts +1 -0
- package/dist/index-BVVgDSdq.d.ts +1 -0
- package/dist/index.cjs +8 -2
- package/dist/index.d.cts +14 -16
- package/dist/index.d.ts +14 -16
- package/dist/index.js +4 -3
- package/dist/{mobileErrorCodes-CmjYEIYm.d.ts → mobileErrorCodes-CdwX6QTO.d.cts} +8 -3
- package/dist/mobileErrorCodes-CdwX6QTO.d.cts.map +1 -0
- package/dist/{mobileErrorCodes-CmjYEIYm.d.cts → mobileErrorCodes-CdwX6QTO.d.ts} +8 -3
- package/dist/mobileErrorCodes-CdwX6QTO.d.ts.map +1 -0
- package/dist/{payloadHash-DhHmgRqL.d.cts → payloadHash-BgGSZock.d.cts} +2 -2
- package/dist/payloadHash-BgGSZock.d.cts.map +1 -0
- package/dist/{payloadHash-E1_8fpLW.d.ts → payloadHash-Bi6upCLQ.d.ts} +2 -2
- package/dist/payloadHash-Bi6upCLQ.d.ts.map +1 -0
- package/dist/{serverExecuteTypes-BwWGspOg.d.ts → serverExecuteTypes-DuCWe_H_.d.cts} +23 -14
- package/dist/serverExecuteTypes-DuCWe_H_.d.cts.map +1 -0
- package/dist/{serverExecuteTypes-B-OJok19.d.cts → serverExecuteTypes-usJ6HMJv.d.ts} +23 -14
- package/dist/serverExecuteTypes-usJ6HMJv.d.ts.map +1 -0
- package/dist/{serverModelTypes-CiA-dy1R.d.ts → serverModelTypes-CTHMNIQS.d.cts} +170 -13
- package/dist/serverModelTypes-CTHMNIQS.d.cts.map +1 -0
- package/dist/{serverModelTypes-CiA-dy1R.d.cts → serverModelTypes-CTHMNIQS.d.ts} +170 -13
- package/dist/serverModelTypes-CTHMNIQS.d.ts.map +1 -0
- package/dist/{serverResponseGuards-CShiXpHT.d.ts → serverResponseGuards-CzmldAad.d.cts} +2 -2
- package/dist/{serverResponseGuards-BW69PS7O.d.cts.map → serverResponseGuards-CzmldAad.d.cts.map} +1 -1
- package/dist/{serverResponseGuards-BW69PS7O.d.cts → serverResponseGuards-Dvkbjp2_.d.ts} +2 -2
- package/dist/{serverResponseGuards-CShiXpHT.d.ts.map → serverResponseGuards-Dvkbjp2_.d.ts.map} +1 -1
- package/dist/signing/buildSignedMobileRequest.d.cts +1 -1
- package/dist/signing/buildSignedMobileRequest.d.ts +1 -1
- package/dist/signing/canonicalize.cjs +53 -2
- package/dist/signing/canonicalize.cjs.map +1 -1
- package/dist/signing/canonicalize.d.cts +1 -1
- package/dist/signing/canonicalize.d.ts +1 -1
- package/dist/signing/canonicalize.js +53 -2
- package/dist/signing/canonicalize.js.map +1 -1
- package/dist/signing/eip712MethodByType.cjs +7 -0
- package/dist/signing/eip712MethodByType.cjs.map +1 -1
- package/dist/signing/eip712MethodByType.d.cts +1 -1
- package/dist/signing/eip712MethodByType.d.ts +1 -1
- package/dist/signing/eip712MethodByType.js +7 -0
- package/dist/signing/eip712MethodByType.js.map +1 -1
- package/dist/signing/index.d.cts +5 -5
- package/dist/signing/index.d.ts +5 -5
- package/dist/signing/payloadHash.cjs +1 -1
- package/dist/signing/payloadHash.d.cts +1 -1
- package/dist/signing/payloadHash.d.ts +1 -1
- package/dist/signing/payloadHash.js +1 -1
- package/dist/signing/types.d.cts +1 -1
- package/dist/signing/types.d.ts +1 -1
- package/dist/types/MobileServerFailureError.d.cts +1 -1
- package/dist/types/MobileServerFailureError.d.ts +1 -1
- package/dist/types/MobileUnsupportedNotificationRouteError.cjs +19 -0
- package/dist/types/MobileUnsupportedNotificationRouteError.cjs.map +1 -0
- package/dist/types/MobileUnsupportedNotificationRouteError.d.cts +2 -0
- package/dist/types/MobileUnsupportedNotificationRouteError.d.ts +2 -0
- package/dist/types/MobileUnsupportedNotificationRouteError.js +18 -0
- package/dist/types/MobileUnsupportedNotificationRouteError.js.map +1 -0
- package/dist/types/clientTypes.d.cts +2 -2
- package/dist/types/clientTypes.d.ts +2 -2
- package/dist/types/index.cjs +4 -0
- package/dist/types/index.d.cts +8 -9
- package/dist/types/index.d.ts +8 -9
- package/dist/types/index.js +3 -2
- package/dist/types/mobileErrorCodes.cjs +11 -1
- package/dist/types/mobileErrorCodes.cjs.map +1 -1
- package/dist/types/mobileErrorCodes.d.cts +1 -1
- package/dist/types/mobileErrorCodes.d.ts +1 -1
- package/dist/types/mobileErrorCodes.js +11 -1
- package/dist/types/mobileErrorCodes.js.map +1 -1
- package/dist/types/serverBaseTypes.d.cts +1 -1
- package/dist/types/serverBaseTypes.d.ts +1 -1
- package/dist/types/serverExecuteTypes.d.cts +2 -2
- package/dist/types/serverExecuteTypes.d.ts +2 -2
- package/dist/types/serverModelTypes.cjs +15 -0
- package/dist/types/serverModelTypes.cjs.map +1 -1
- package/dist/types/serverModelTypes.d.cts +2 -2
- package/dist/types/serverModelTypes.d.ts +2 -2
- package/dist/types/serverModelTypes.js +14 -1
- package/dist/types/serverModelTypes.js.map +1 -1
- package/dist/types/serverQueryTypes.d.cts +2 -2
- package/dist/types/serverQueryTypes.d.ts +2 -2
- package/dist/types/serverRequestTypes.d.cts +2 -2
- package/dist/types/serverRequestTypes.d.ts +2 -2
- package/dist/types-CByl_NyJ.d.ts +825 -0
- package/dist/types-CByl_NyJ.d.ts.map +1 -0
- package/dist/types-CR5iaKR4.d.cts +825 -0
- package/dist/types-CR5iaKR4.d.cts.map +1 -0
- package/dist/utils/buildMobileFeedImageMultipart.cjs +31 -0
- package/dist/utils/buildMobileFeedImageMultipart.cjs.map +1 -0
- package/dist/utils/buildMobileFeedImageMultipart.d.cts +15 -0
- package/dist/utils/buildMobileFeedImageMultipart.d.cts.map +1 -0
- package/dist/utils/buildMobileFeedImageMultipart.d.ts +15 -0
- package/dist/utils/buildMobileFeedImageMultipart.d.ts.map +1 -0
- package/dist/utils/buildMobileFeedImageMultipart.js +30 -0
- package/dist/utils/buildMobileFeedImageMultipart.js.map +1 -0
- package/dist/utils/feed.cjs +12 -0
- package/dist/utils/feed.cjs.map +1 -1
- package/dist/utils/feed.d.cts +2 -2
- package/dist/utils/feed.d.ts +2 -2
- package/dist/utils/feed.js +11 -1
- package/dist/utils/feed.js.map +1 -1
- package/dist/utils/index.cjs +3 -1
- package/dist/utils/index.d.cts +3 -3
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +2 -2
- package/dist/utils/serverResponseGuards.d.cts +1 -1
- package/dist/utils/serverResponseGuards.d.ts +1 -1
- package/package.json +3 -3
- package/src/MobileClient.ts +444 -19
- package/src/dataMappers.test.ts +511 -6
- package/src/dataMappers.ts +325 -24
- package/src/feedImages.test.ts +309 -0
- package/src/notifications.test.ts +950 -0
- package/src/signing/canonicalize.ts +72 -0
- package/src/signing/eip712MethodByType.ts +10 -0
- package/src/signing/signing.test.ts +67 -1
- package/src/signing/types.ts +55 -9
- package/src/socialFeed.test.ts +63 -2
- package/src/types/MobileUnsupportedNotificationRouteError.ts +16 -0
- package/src/types/clientTypes.ts +427 -36
- package/src/types/index.ts +1 -0
- package/src/types/mobileErrorCodes.ts +10 -0
- package/src/types/serverExecuteTypes.ts +22 -10
- package/src/types/serverModelTypes.ts +216 -11
- package/src/types/serverQueryTypes.ts +106 -9
- package/src/types/serverRequestTypes.ts +114 -17
- package/src/utils/buildMobileFeedImageMultipart.test.ts +45 -0
- package/src/utils/buildMobileFeedImageMultipart.ts +36 -0
- package/src/utils/feed.ts +16 -0
- package/dist/MobileClient-CfVZXTcz.cjs.map +0 -1
- package/dist/MobileServerFailureError-BZVwlsMg.d.ts.map +0 -1
- package/dist/MobileServerFailureError-CbtK8kD4.d.cts.map +0 -1
- package/dist/canonicalize-5eeZrkzQ.d.ts.map +0 -1
- package/dist/canonicalize-CBaZprTo.d.cts.map +0 -1
- package/dist/clientTypes-C9dJufxk.d.ts.map +0 -1
- package/dist/clientTypes-_mEgzmNs.d.cts.map +0 -1
- package/dist/eip712MethodByType-D8jLoxDu.d.cts.map +0 -1
- package/dist/eip712MethodByType-DcUh8h-l.d.ts.map +0 -1
- package/dist/feed-DTJlsg8W.d.cts +0 -14
- package/dist/feed-DTJlsg8W.d.cts.map +0 -1
- package/dist/feed-DTJlsg8W.d.ts +0 -14
- package/dist/feed-DTJlsg8W.d.ts.map +0 -1
- package/dist/mobileErrorCodes-CmjYEIYm.d.cts.map +0 -1
- package/dist/mobileErrorCodes-CmjYEIYm.d.ts.map +0 -1
- package/dist/payloadHash-DhHmgRqL.d.cts.map +0 -1
- package/dist/payloadHash-E1_8fpLW.d.ts.map +0 -1
- package/dist/serverBaseTypes-B5J1_TyC.d.cts +0 -25
- package/dist/serverBaseTypes-B5J1_TyC.d.cts.map +0 -1
- package/dist/serverBaseTypes-DnLzsdm-.d.ts +0 -25
- package/dist/serverBaseTypes-DnLzsdm-.d.ts.map +0 -1
- package/dist/serverExecuteTypes-B-OJok19.d.cts.map +0 -1
- package/dist/serverExecuteTypes-BwWGspOg.d.ts.map +0 -1
- package/dist/serverModelTypes-CiA-dy1R.d.cts.map +0 -1
- package/dist/serverModelTypes-CiA-dy1R.d.ts.map +0 -1
- package/dist/serverQueryTypes-CJcjLB7n.d.ts +0 -283
- package/dist/serverQueryTypes-CJcjLB7n.d.ts.map +0 -1
- package/dist/serverQueryTypes-V1f9yE7L.d.cts +0 -283
- package/dist/serverQueryTypes-V1f9yE7L.d.cts.map +0 -1
- package/dist/serverRequestTypes-CRlkNSu5.d.cts +0 -270
- package/dist/serverRequestTypes-CRlkNSu5.d.cts.map +0 -1
- package/dist/serverRequestTypes-DZoOhV2o.d.ts +0 -270
- package/dist/serverRequestTypes-DZoOhV2o.d.ts.map +0 -1
- package/dist/types-BiRmH5Iv.d.cts +0 -108
- package/dist/types-BiRmH5Iv.d.cts.map +0 -1
- package/dist/types-DoJuq0Ij.d.ts +0 -108
- package/dist/types-DoJuq0Ij.d.ts.map +0 -1
|
@@ -12,6 +12,60 @@ export function canonicalizeMobileInner(
|
|
|
12
12
|
inner: MobileSignedInner,
|
|
13
13
|
): MobileSignedInner {
|
|
14
14
|
switch (inner.type) {
|
|
15
|
+
case 'register_expo_token_v2':
|
|
16
|
+
return {
|
|
17
|
+
type: inner.type,
|
|
18
|
+
expo_token: inner.expo_token,
|
|
19
|
+
platform: inner.platform,
|
|
20
|
+
locale: inner.locale,
|
|
21
|
+
app_version: inner.app_version,
|
|
22
|
+
capabilities: {
|
|
23
|
+
payload_versions: [...inner.capabilities.payload_versions],
|
|
24
|
+
type_ids: [...inner.capabilities.type_ids],
|
|
25
|
+
routes: [...inner.capabilities.routes],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
case 'notification_subscriptions':
|
|
29
|
+
return { type: inner.type };
|
|
30
|
+
case 'update_notification_subscriptions':
|
|
31
|
+
return {
|
|
32
|
+
type: inner.type,
|
|
33
|
+
expected_revision: inner.expected_revision,
|
|
34
|
+
trader_bell:
|
|
35
|
+
inner.trader_bell == null
|
|
36
|
+
? null
|
|
37
|
+
: {
|
|
38
|
+
subaccount: inner.trader_bell.subaccount,
|
|
39
|
+
enabled: inner.trader_bell.enabled,
|
|
40
|
+
},
|
|
41
|
+
market:
|
|
42
|
+
inner.market == null
|
|
43
|
+
? null
|
|
44
|
+
: {
|
|
45
|
+
product_id: inner.market.product_id,
|
|
46
|
+
subscribed: inner.market.subscribed,
|
|
47
|
+
},
|
|
48
|
+
import_markets:
|
|
49
|
+
inner.import_markets == null ? null : [...inner.import_markets],
|
|
50
|
+
};
|
|
51
|
+
case 'notification_inbox_v2':
|
|
52
|
+
return {
|
|
53
|
+
type: inner.type,
|
|
54
|
+
cursor: inner.cursor,
|
|
55
|
+
limit: inner.limit,
|
|
56
|
+
};
|
|
57
|
+
case 'record_product_events':
|
|
58
|
+
return {
|
|
59
|
+
type: inner.type,
|
|
60
|
+
events: inner.events.map((event) => ({
|
|
61
|
+
client_event_id: event.client_event_id,
|
|
62
|
+
event_name: event.event_name,
|
|
63
|
+
notification_id: event.notification_id,
|
|
64
|
+
occurred_at: event.occurred_at,
|
|
65
|
+
product_id: event.product_id,
|
|
66
|
+
query: event.query,
|
|
67
|
+
})),
|
|
68
|
+
};
|
|
15
69
|
case 'create_feed_post':
|
|
16
70
|
return {
|
|
17
71
|
type: inner.type,
|
|
@@ -25,6 +79,12 @@ export function canonicalizeMobileInner(
|
|
|
25
79
|
...(inner.drawing_data_json === undefined
|
|
26
80
|
? {}
|
|
27
81
|
: { drawing_data_json: inner.drawing_data_json }),
|
|
82
|
+
...(inner.image_ids === undefined
|
|
83
|
+
? {}
|
|
84
|
+
: { image_ids: [...inner.image_ids] }),
|
|
85
|
+
...(inner.image_urls === undefined
|
|
86
|
+
? {}
|
|
87
|
+
: { image_urls: [...inner.image_urls] }),
|
|
28
88
|
};
|
|
29
89
|
case 'create_feed_comment':
|
|
30
90
|
return {
|
|
@@ -39,6 +99,18 @@ export function canonicalizeMobileInner(
|
|
|
39
99
|
...(inner.attached_position_id === undefined
|
|
40
100
|
? {}
|
|
41
101
|
: { attached_position_id: inner.attached_position_id }),
|
|
102
|
+
...(inner.image_ids === undefined
|
|
103
|
+
? {}
|
|
104
|
+
: { image_ids: [...inner.image_ids] }),
|
|
105
|
+
...(inner.image_urls === undefined
|
|
106
|
+
? {}
|
|
107
|
+
: { image_urls: [...inner.image_urls] }),
|
|
108
|
+
};
|
|
109
|
+
case 'create_feed_post_image_uploads':
|
|
110
|
+
case 'create_feed_comment_image_uploads':
|
|
111
|
+
return {
|
|
112
|
+
type: inner.type,
|
|
113
|
+
content_hash: inner.content_hash,
|
|
42
114
|
};
|
|
43
115
|
case 'create_feed_chart_drawing':
|
|
44
116
|
case 'update_feed_chart_drawing':
|
|
@@ -7,8 +7,18 @@ export const MOBILE_EIP712_METHOD_BY_TYPE: Record<
|
|
|
7
7
|
MobileSignedInner['type'],
|
|
8
8
|
string
|
|
9
9
|
> = {
|
|
10
|
+
register_expo_token_v2: 'mobile:execute_register_expo_token_v2',
|
|
11
|
+
notification_subscriptions: 'mobile:query_notification_subscriptions',
|
|
12
|
+
update_notification_subscriptions:
|
|
13
|
+
'mobile:execute_update_notification_subscriptions',
|
|
14
|
+
notification_inbox_v2: 'mobile:query_notification_inbox_v2',
|
|
15
|
+
record_product_events: 'mobile:execute_record_product_events',
|
|
10
16
|
create_feed_post: 'mobile:execute_create_feed_post',
|
|
11
17
|
create_feed_comment: 'mobile:execute_create_feed_comment',
|
|
18
|
+
create_feed_post_image_uploads:
|
|
19
|
+
'mobile:execute_create_feed_post_image_uploads',
|
|
20
|
+
create_feed_comment_image_uploads:
|
|
21
|
+
'mobile:execute_create_feed_comment_image_uploads',
|
|
12
22
|
create_feed_chart_drawing: 'mobile:execute_create_feed_chart_drawing',
|
|
13
23
|
update_feed_chart_drawing: 'mobile:execute_update_feed_chart_drawing',
|
|
14
24
|
set_feed_like: 'mobile:execute_set_feed_like',
|
|
@@ -435,7 +435,9 @@ describe('[mobile-client]: social content signing', () => {
|
|
|
435
435
|
const drawing = ' { "lines" : [], "enabled": false } ';
|
|
436
436
|
|
|
437
437
|
it('canonicalizes every post field and nested mention without changing content', () => {
|
|
438
|
+
const imageIds = ['88888888-8888-4888-8888-888888888888'];
|
|
438
439
|
const input: MobileSignedInner = {
|
|
440
|
+
image_ids: imageIds,
|
|
439
441
|
drawing_data_json: drawing,
|
|
440
442
|
mentions: [mention],
|
|
441
443
|
text,
|
|
@@ -453,6 +455,7 @@ describe('[mobile-client]: social content signing', () => {
|
|
|
453
455
|
'text',
|
|
454
456
|
'mentions',
|
|
455
457
|
'drawing_data_json',
|
|
458
|
+
'image_ids',
|
|
456
459
|
]);
|
|
457
460
|
if (result.type !== 'create_feed_post') throw new Error('Expected post');
|
|
458
461
|
expect(Object.keys(result.mentions[0])).toEqual([
|
|
@@ -466,6 +469,8 @@ describe('[mobile-client]: social content signing', () => {
|
|
|
466
469
|
expect(result.position_id).toBe(positionId);
|
|
467
470
|
expect(result.text).toBe(text);
|
|
468
471
|
expect(result.drawing_data_json).toBe(drawing);
|
|
472
|
+
expect(result.image_ids).toEqual(imageIds);
|
|
473
|
+
expect(result.image_ids).not.toBe(imageIds);
|
|
469
474
|
expect(result.mentions[0]).toEqual({
|
|
470
475
|
subaccount: FIXTURE_TARGET_SUBACCOUNT,
|
|
471
476
|
start: 2,
|
|
@@ -582,6 +587,16 @@ describe('[mobile-client]: social content signing', () => {
|
|
|
582
587
|
});
|
|
583
588
|
|
|
584
589
|
const payloads: MobileSignedInner[] = [
|
|
590
|
+
{
|
|
591
|
+
type: 'create_feed_post_image_uploads',
|
|
592
|
+
content_hash:
|
|
593
|
+
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
594
|
+
},
|
|
595
|
+
{
|
|
596
|
+
type: 'create_feed_comment_image_uploads',
|
|
597
|
+
content_hash:
|
|
598
|
+
'0xaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
599
|
+
},
|
|
585
600
|
{
|
|
586
601
|
type: 'create_feed_post',
|
|
587
602
|
client_request_id: requestId,
|
|
@@ -633,8 +648,59 @@ describe('[mobile-client]: social content signing', () => {
|
|
|
633
648
|
signature: signed.signature,
|
|
634
649
|
});
|
|
635
650
|
expect(recovered.toLowerCase()).toBe(account.address.toLowerCase());
|
|
636
|
-
expect(signed).toMatchObject(canonical);
|
|
651
|
+
expect(signed).toMatchObject({ ...canonical });
|
|
637
652
|
expect(signed).not.toHaveProperty('payload');
|
|
638
653
|
},
|
|
639
654
|
);
|
|
640
655
|
});
|
|
656
|
+
|
|
657
|
+
describe('[mobile-client]: external image signing', () => {
|
|
658
|
+
it.each(['create_feed_post', 'create_feed_comment'] as const)(
|
|
659
|
+
'signs ordered original URL arrays after image_ids for %s',
|
|
660
|
+
(type) => {
|
|
661
|
+
const base = {
|
|
662
|
+
client_request_id: '11111111-1111-4111-8111-111111111111',
|
|
663
|
+
text: 'image test',
|
|
664
|
+
mentions: [],
|
|
665
|
+
};
|
|
666
|
+
const inner: MobileSignedInner =
|
|
667
|
+
type === 'create_feed_post'
|
|
668
|
+
? {
|
|
669
|
+
type,
|
|
670
|
+
...base,
|
|
671
|
+
position_id: '22222222-2222-4222-8222-222222222222',
|
|
672
|
+
}
|
|
673
|
+
: {
|
|
674
|
+
type,
|
|
675
|
+
...base,
|
|
676
|
+
root_item_id: '22222222-2222-4222-8222-222222222222',
|
|
677
|
+
};
|
|
678
|
+
const urls = [
|
|
679
|
+
'https://example.com/A.png?x=%2f',
|
|
680
|
+
'https://example.com/b.png',
|
|
681
|
+
];
|
|
682
|
+
const result = canonicalizeMobileInner({
|
|
683
|
+
image_urls: urls,
|
|
684
|
+
image_ids: [],
|
|
685
|
+
...inner,
|
|
686
|
+
});
|
|
687
|
+
expect(Object.keys(result).slice(-2)).toEqual([
|
|
688
|
+
'image_ids',
|
|
689
|
+
'image_urls',
|
|
690
|
+
]);
|
|
691
|
+
if (result.type !== type) throw new Error('Unexpected signing type');
|
|
692
|
+
expect(result.image_urls).toEqual(urls);
|
|
693
|
+
expect(result.image_urls).not.toBe(urls);
|
|
694
|
+
const hash = (imageUrls?: string[]) =>
|
|
695
|
+
getMobilePayloadHash(
|
|
696
|
+
canonicalizeMobileInner({ ...inner, image_urls: imageUrls }),
|
|
697
|
+
);
|
|
698
|
+
expect(hash()).not.toBe(hash([]));
|
|
699
|
+
expect(hash(urls)).not.toBe(hash([...urls].reverse()));
|
|
700
|
+
expect(hash(urls)).not.toBe(
|
|
701
|
+
hash([urls[0].replace('%2f', '%2F'), urls[1]]),
|
|
702
|
+
);
|
|
703
|
+
expect(hash(urls)).toBe(hash([...urls]));
|
|
704
|
+
},
|
|
705
|
+
);
|
|
706
|
+
});
|
package/src/signing/types.ts
CHANGED
|
@@ -2,10 +2,15 @@ import { WalletClientWithAccount } from '@nadohq/shared';
|
|
|
2
2
|
import { Hex } from 'viem';
|
|
3
3
|
import { MobileSignedRequestParams } from '../types/clientTypes';
|
|
4
4
|
import {
|
|
5
|
-
MobileNotificationPlatform,
|
|
6
5
|
MobileServerAvatarSelection,
|
|
6
|
+
MobileServerProductEvent,
|
|
7
7
|
MobileSocialFeedMention,
|
|
8
8
|
} from '../types/serverModelTypes';
|
|
9
|
+
import {
|
|
10
|
+
MobileServerNotificationSubscriptionsUpdate,
|
|
11
|
+
MobileServerRegisterExpoTokenParams,
|
|
12
|
+
MobileServerRegisterExpoTokenV2Params,
|
|
13
|
+
} from '../types/serverRequestTypes';
|
|
9
14
|
|
|
10
15
|
/**
|
|
11
16
|
* Unsigned inner payloads that can be authenticated against the mobile service API.
|
|
@@ -22,6 +27,32 @@ import {
|
|
|
22
27
|
* lowercases; unlike bytes32, string fields such as `display_name` are hashed as-is and keep their casing.
|
|
23
28
|
*/
|
|
24
29
|
export type MobileSignedInner =
|
|
30
|
+
| ({
|
|
31
|
+
/** Capability-aware device registration. */
|
|
32
|
+
type: 'register_expo_token_v2';
|
|
33
|
+
} & MobileServerRegisterExpoTokenV2Params)
|
|
34
|
+
| {
|
|
35
|
+
/** Signed query for wallet markets and Identity bells. */
|
|
36
|
+
type: 'notification_subscriptions';
|
|
37
|
+
}
|
|
38
|
+
| ({
|
|
39
|
+
/** One revision-guarded subscription operation. */
|
|
40
|
+
type: 'update_notification_subscriptions';
|
|
41
|
+
} & MobileServerNotificationSubscriptionsUpdate)
|
|
42
|
+
| {
|
|
43
|
+
/** Signed query for the wallet's private notification page. */
|
|
44
|
+
type: 'notification_inbox_v2';
|
|
45
|
+
/** Previous page cursor, or nil for the first page. */
|
|
46
|
+
cursor: string | null;
|
|
47
|
+
/** Page size, or nil for the server default. */
|
|
48
|
+
limit: number | null;
|
|
49
|
+
}
|
|
50
|
+
| {
|
|
51
|
+
/** Atomic product analytics batch. */
|
|
52
|
+
type: 'record_product_events';
|
|
53
|
+
/** Events in caller order. */
|
|
54
|
+
events: MobileServerProductEvent[];
|
|
55
|
+
}
|
|
25
56
|
| {
|
|
26
57
|
/** Atomic post publication. */
|
|
27
58
|
type: 'create_feed_post';
|
|
@@ -37,6 +68,10 @@ export type MobileSignedInner =
|
|
|
37
68
|
mentions: MobileSocialFeedMention[];
|
|
38
69
|
/** Original JSON text; omitted when absent. */
|
|
39
70
|
drawing_data_json?: string;
|
|
71
|
+
/** Ordered ready image UUIDs; omitted when absent. */
|
|
72
|
+
image_ids?: string[];
|
|
73
|
+
/** Up to ten original HTTP/HTTPS URLs in order; omission differs from an empty array. */
|
|
74
|
+
image_urls?: string[];
|
|
40
75
|
}
|
|
41
76
|
| {
|
|
42
77
|
/** Atomic comment publication. */
|
|
@@ -53,6 +88,22 @@ export type MobileSignedInner =
|
|
|
53
88
|
mentions: MobileSocialFeedMention[];
|
|
54
89
|
/** Optional owned position UUID. */
|
|
55
90
|
attached_position_id?: string;
|
|
91
|
+
/** Ordered ready image UUIDs; omitted when absent. */
|
|
92
|
+
image_ids?: string[];
|
|
93
|
+
/** Up to ten original HTTP/HTTPS URLs in order; omission differs from an empty array. */
|
|
94
|
+
image_urls?: string[];
|
|
95
|
+
}
|
|
96
|
+
| {
|
|
97
|
+
/** Direct multipart post-image upload; content_hash is Keccak256 of the raw file bytes. */
|
|
98
|
+
type: 'create_feed_post_image_uploads';
|
|
99
|
+
/** `0x`-prefixed lowercase Keccak256 of the original file bytes. */
|
|
100
|
+
content_hash: Hex;
|
|
101
|
+
}
|
|
102
|
+
| {
|
|
103
|
+
/** Direct multipart comment-image upload; content_hash is Keccak256 of the raw file bytes. */
|
|
104
|
+
type: 'create_feed_comment_image_uploads';
|
|
105
|
+
/** `0x`-prefixed lowercase Keccak256 of the original file bytes. */
|
|
106
|
+
content_hash: Hex;
|
|
56
107
|
}
|
|
57
108
|
| {
|
|
58
109
|
/** First attachment. */
|
|
@@ -86,15 +137,10 @@ export type MobileSignedInner =
|
|
|
86
137
|
}
|
|
87
138
|
| { type: 'set_username'; display_name: string }
|
|
88
139
|
| { type: 'set_private_mode'; private_mode: boolean }
|
|
89
|
-
| {
|
|
140
|
+
| ({
|
|
141
|
+
/** Legacy device registration without a capability declaration. */
|
|
90
142
|
type: 'register_expo_token';
|
|
91
|
-
|
|
92
|
-
platform: MobileNotificationPlatform;
|
|
93
|
-
// Optional on the wire, but always present (null when unset) so the msgpack payload hash matches the
|
|
94
|
-
// backend, which serializes `Option::None` as nil under the same key.
|
|
95
|
-
locale: string | null;
|
|
96
|
-
app_version: string | null;
|
|
97
|
-
}
|
|
143
|
+
} & MobileServerRegisterExpoTokenParams)
|
|
98
144
|
| {
|
|
99
145
|
type: 'set_follow';
|
|
100
146
|
subaccount: Hex;
|
package/src/socialFeed.test.ts
CHANGED
|
@@ -82,7 +82,7 @@ const readSession: MobileServerSocialFeedReadSession = {
|
|
|
82
82
|
session_id: 'OpaqueSession',
|
|
83
83
|
mode: 'feed',
|
|
84
84
|
expires_at_ms: 42,
|
|
85
|
-
|
|
85
|
+
|
|
86
86
|
update_cursor: null,
|
|
87
87
|
viewer_token: 'OpaqueViewer',
|
|
88
88
|
};
|
|
@@ -222,6 +222,7 @@ describe('[mobile-client]: social feed transport', () => {
|
|
|
222
222
|
expect(requests[3].body.subaccount).not.toBe(requests[3].body.view_as);
|
|
223
223
|
expect(requests[5].body.position_id).toBe(positionId.toUpperCase());
|
|
224
224
|
expect(requests[6].body.item_id).toBe(itemId.toUpperCase());
|
|
225
|
+
expect(requests[6].body).not.toHaveProperty('view_event_id');
|
|
225
226
|
expect(requests[6].body.comment_preview_limit).toBe(0);
|
|
226
227
|
expect(requests[7].body).toEqual({
|
|
227
228
|
type: 'feed_updates',
|
|
@@ -235,6 +236,65 @@ describe('[mobile-client]: social feed transport', () => {
|
|
|
235
236
|
},
|
|
236
237
|
);
|
|
237
238
|
|
|
239
|
+
it('reports multiple IDs and same-request duplicates without session fields or a signature', async () => {
|
|
240
|
+
const { client, requests } = mockClient({ status: 'success' });
|
|
241
|
+
client.opts.walletClient = undefined;
|
|
242
|
+
const itemIds = [itemId, 'cccccccc-cccc-4ccc-8ccc-cccccccccccc', itemId];
|
|
243
|
+
expect(await client.recordFeedViews({ itemIds })).toEqual({
|
|
244
|
+
status: 'success',
|
|
245
|
+
});
|
|
246
|
+
expect(requests).toEqual([
|
|
247
|
+
{
|
|
248
|
+
url: 'https://mobile.example/v1/mobile/public_execute',
|
|
249
|
+
body: { type: 'record_feed_views', item_ids: itemIds },
|
|
250
|
+
},
|
|
251
|
+
]);
|
|
252
|
+
// A caller-initiated repeat remains a new report, not a cached or locally deduplicated result.
|
|
253
|
+
await client.recordFeedViews({ itemIds });
|
|
254
|
+
expect(requests).toHaveLength(2);
|
|
255
|
+
expect(requests[1].body).toEqual(requests[0].body);
|
|
256
|
+
});
|
|
257
|
+
|
|
258
|
+
it.each([
|
|
259
|
+
[400, 6310],
|
|
260
|
+
[503, 1006],
|
|
261
|
+
[503, 6320],
|
|
262
|
+
])(
|
|
263
|
+
'preserves batch view failures (%i/%i) without retrying',
|
|
264
|
+
async (httpStatus, errorCode) => {
|
|
265
|
+
const { client, requests } = mockClient(
|
|
266
|
+
{
|
|
267
|
+
status: 'failure',
|
|
268
|
+
error: 'Batch rejected',
|
|
269
|
+
error_code: errorCode,
|
|
270
|
+
request_type: 'public_execute_record_feed_views',
|
|
271
|
+
},
|
|
272
|
+
httpStatus,
|
|
273
|
+
);
|
|
274
|
+
await expect(
|
|
275
|
+
client.recordFeedViews({ itemIds: [itemId] }),
|
|
276
|
+
).rejects.toMatchObject({
|
|
277
|
+
name: 'MobileServerFailureError',
|
|
278
|
+
errorCode,
|
|
279
|
+
httpStatus,
|
|
280
|
+
});
|
|
281
|
+
expect(requests).toHaveLength(1);
|
|
282
|
+
},
|
|
283
|
+
);
|
|
284
|
+
|
|
285
|
+
it('does not retry a view report when the response may have been lost', async () => {
|
|
286
|
+
const { client } = mockClient();
|
|
287
|
+
let attempts = 0;
|
|
288
|
+
client.axiosInstance.defaults.adapter = () => {
|
|
289
|
+
attempts++;
|
|
290
|
+
return Promise.reject(new Error('Connection closed after sending'));
|
|
291
|
+
};
|
|
292
|
+
await expect(client.recordFeedViews({ itemIds: [itemId] })).rejects.toThrow(
|
|
293
|
+
'Connection closed',
|
|
294
|
+
);
|
|
295
|
+
expect(attempts).toBe(1);
|
|
296
|
+
});
|
|
297
|
+
|
|
238
298
|
it('preserves update IDs, session credentials, and cursors unchanged', async () => {
|
|
239
299
|
const { client, requests } = mockClient();
|
|
240
300
|
client.opts.walletClient = undefined;
|
|
@@ -309,7 +369,7 @@ describe('[mobile-client]: social feed transport', () => {
|
|
|
309
369
|
session_id: 'Session',
|
|
310
370
|
mode: 'feed',
|
|
311
371
|
expires_at_ms: 42,
|
|
312
|
-
|
|
372
|
+
|
|
313
373
|
update_cursor: null,
|
|
314
374
|
viewer_token: 'Viewer',
|
|
315
375
|
},
|
|
@@ -660,6 +720,7 @@ describe('[mobile-client]: social feed response mapping', () => {
|
|
|
660
720
|
...row,
|
|
661
721
|
kind: 'trade_card',
|
|
662
722
|
action: 'opened',
|
|
723
|
+
images: [],
|
|
663
724
|
text: '',
|
|
664
725
|
mentions: [],
|
|
665
726
|
author: {
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Error thrown when the mobile service returns a notification route this SDK does not support.
|
|
3
|
+
*/
|
|
4
|
+
export class MobileUnsupportedNotificationRouteError extends Error {
|
|
5
|
+
/** Unrecognized route name returned by the service. */
|
|
6
|
+
readonly routeName: string;
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* @param routeName - The unrecognized service route name.
|
|
10
|
+
*/
|
|
11
|
+
constructor(routeName: string) {
|
|
12
|
+
super(`Unsupported mobile notification route "${routeName}".`);
|
|
13
|
+
this.name = 'MobileUnsupportedNotificationRouteError';
|
|
14
|
+
this.routeName = routeName;
|
|
15
|
+
}
|
|
16
|
+
}
|