@oxyhq/core 3.4.16 → 3.4.17
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/dist/cjs/.tsbuildinfo +1 -1
- package/dist/cjs/AuthManager.js +5 -0
- package/dist/cjs/mixins/OxyServices.auth.js +1 -1
- package/dist/cjs/mixins/OxyServices.sso.js +2 -1
- package/dist/cjs/mixins/OxyServices.user.js +1 -1
- package/dist/cjs/utils/accountUtils.js +16 -11
- package/dist/esm/.tsbuildinfo +1 -1
- package/dist/esm/AuthManager.js +5 -0
- package/dist/esm/mixins/OxyServices.auth.js +1 -1
- package/dist/esm/mixins/OxyServices.sso.js +2 -1
- package/dist/esm/mixins/OxyServices.user.js +1 -1
- package/dist/esm/utils/accountUtils.js +16 -11
- package/dist/types/.tsbuildinfo +1 -1
- package/dist/types/mixins/OxyServices.user.d.ts +5 -8
- package/dist/types/models/interfaces.d.ts +11 -12
- package/dist/types/models/session.d.ts +2 -0
- package/dist/types/utils/accountUtils.d.ts +10 -7
- package/package.json +2 -2
- package/src/AuthManager.ts +6 -1
- package/src/mixins/OxyServices.auth.ts +1 -1
- package/src/mixins/OxyServices.sso.ts +4 -1
- package/src/mixins/OxyServices.user.ts +5 -4
- package/src/models/interfaces.ts +11 -12
- package/src/models/session.ts +3 -0
- package/src/utils/__tests__/accountUtils.test.ts +3 -4
- package/src/utils/accountUtils.ts +26 -15
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
* User Management Methods Mixin
|
|
3
3
|
*/
|
|
4
4
|
import type { User, Notification, NotificationPreferences, UserPreferences, SearchProfilesResponse, PrivacySettings } from '../models/interfaces';
|
|
5
|
+
import type { UserNameResponse, UserProfileUpdate } from '@oxyhq/contracts';
|
|
5
6
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
6
7
|
import { type PaginationParams } from '../utils/apiUtils';
|
|
7
8
|
export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T): {
|
|
@@ -12,7 +13,7 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
12
13
|
getProfileByUsername(username: string): Promise<User>;
|
|
13
14
|
/**
|
|
14
15
|
* Lightweight username lookup for login flows.
|
|
15
|
-
* Returns minimal public info: exists, color, avatar, displayName.
|
|
16
|
+
* Returns minimal public info: exists, color, avatar, name.displayName.
|
|
16
17
|
* Faster than getProfileByUsername — no stats, no formatting.
|
|
17
18
|
*/
|
|
18
19
|
lookupUsername(username: string): Promise<{
|
|
@@ -20,7 +21,7 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
20
21
|
username: string;
|
|
21
22
|
color: string | null;
|
|
22
23
|
avatar: string | null;
|
|
23
|
-
|
|
24
|
+
name: UserNameResponse;
|
|
24
25
|
}>;
|
|
25
26
|
/**
|
|
26
27
|
* Search user profiles
|
|
@@ -62,11 +63,7 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
62
63
|
}): Promise<Array<{
|
|
63
64
|
id: string;
|
|
64
65
|
username: string;
|
|
65
|
-
name
|
|
66
|
-
first?: string;
|
|
67
|
-
last?: string;
|
|
68
|
-
full?: string;
|
|
69
|
-
};
|
|
66
|
+
name: UserNameResponse;
|
|
70
67
|
description?: string;
|
|
71
68
|
isFederated?: boolean;
|
|
72
69
|
isAgent?: boolean;
|
|
@@ -111,7 +108,7 @@ export declare function OxyServicesUserMixin<T extends typeof OxyServicesBase>(B
|
|
|
111
108
|
*
|
|
112
109
|
* TanStack Query handles offline queuing automatically.
|
|
113
110
|
*/
|
|
114
|
-
updateProfile(updates:
|
|
111
|
+
updateProfile(updates: UserProfileUpdate): Promise<User>;
|
|
115
112
|
/**
|
|
116
113
|
* Get privacy settings for a user
|
|
117
114
|
* @param userId - The user ID (defaults to current user)
|
|
@@ -80,29 +80,28 @@ export interface User {
|
|
|
80
80
|
id: string;
|
|
81
81
|
publicKey: string;
|
|
82
82
|
username: string;
|
|
83
|
-
/** Canonical display name resolved by the API. */
|
|
84
|
-
displayName: string;
|
|
85
83
|
email?: string;
|
|
86
|
-
avatar?: string;
|
|
87
|
-
color?: string;
|
|
84
|
+
avatar?: string | null;
|
|
85
|
+
color?: string | null;
|
|
88
86
|
privacySettings?: PrivacySettings;
|
|
89
87
|
/**
|
|
90
|
-
* Structured human name.
|
|
91
|
-
*
|
|
92
|
-
*
|
|
93
|
-
* `@oxyhq/contracts` — do NOT re-declare a bare `string` here.
|
|
88
|
+
* Structured human name. `name.displayName` is the canonical display string
|
|
89
|
+
* resolved by the API; consumers render it directly instead of recomposing
|
|
90
|
+
* names from `first` / `last` / `full` / `username`.
|
|
94
91
|
*/
|
|
95
|
-
name
|
|
92
|
+
name: UserNameResponse;
|
|
96
93
|
bio?: string;
|
|
97
94
|
location?: string;
|
|
98
95
|
website?: string;
|
|
99
96
|
createdAt?: string;
|
|
100
97
|
updatedAt?: string;
|
|
101
|
-
links?:
|
|
98
|
+
links?: string[];
|
|
99
|
+
linksMetadata?: Array<{
|
|
100
|
+
url: string;
|
|
102
101
|
title?: string;
|
|
103
102
|
description?: string;
|
|
104
103
|
image?: string;
|
|
105
|
-
|
|
104
|
+
id?: string;
|
|
106
105
|
}>;
|
|
107
106
|
_count?: {
|
|
108
107
|
followers?: number;
|
|
@@ -541,7 +540,7 @@ export interface RefreshAllAccountUser {
|
|
|
541
540
|
* string. The server projects `name` verbatim from the user document. The
|
|
542
541
|
* single source of truth is `@oxyhq/contracts`.
|
|
543
542
|
*/
|
|
544
|
-
name
|
|
543
|
+
name: UserNameResponse;
|
|
545
544
|
avatar?: string | null;
|
|
546
545
|
email?: string;
|
|
547
546
|
color?: string | null;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { UserNameResponse } from '@oxyhq/contracts';
|
|
1
2
|
export interface ClientSession {
|
|
2
3
|
sessionId: string;
|
|
3
4
|
deviceId: string;
|
|
@@ -21,6 +22,7 @@ export interface StorageKeys {
|
|
|
21
22
|
export interface MinimalUserData {
|
|
22
23
|
id: string;
|
|
23
24
|
username: string;
|
|
25
|
+
name: UserNameResponse;
|
|
24
26
|
avatar?: string;
|
|
25
27
|
}
|
|
26
28
|
export interface SessionLoginResponse {
|
|
@@ -27,12 +27,13 @@ export interface QuickAccount {
|
|
|
27
27
|
/** Minimal user shape accepted by display-name helpers. Avoids importing the full User type. */
|
|
28
28
|
export interface DisplayNameUserShape {
|
|
29
29
|
name?: string | {
|
|
30
|
+
displayName?: string;
|
|
30
31
|
first?: string;
|
|
31
32
|
last?: string;
|
|
32
33
|
full?: string;
|
|
33
34
|
[key: string]: unknown;
|
|
34
35
|
};
|
|
35
|
-
/**
|
|
36
|
+
/** Pre-normalized account-row display name, not the API User DTO field. */
|
|
36
37
|
displayName?: string;
|
|
37
38
|
username?: string;
|
|
38
39
|
publicKey?: string;
|
|
@@ -46,12 +47,13 @@ export declare const formatPublicKeyHandle: (publicKey: string) => string;
|
|
|
46
47
|
* Resolve a friendly display name for a user.
|
|
47
48
|
*
|
|
48
49
|
* Order of preference:
|
|
49
|
-
* 1. `displayName` from the API contract.
|
|
50
|
+
* 1. `name.displayName` from the API user contract.
|
|
50
51
|
* 2. `name.full`, or composed `name.first name.last` for local unsaved shapes.
|
|
51
|
-
* 3. `name` when
|
|
52
|
-
* 4. `
|
|
53
|
-
* 5. `
|
|
54
|
-
* 6.
|
|
52
|
+
* 3. `name` when passed as a plain string by local non-DTO call sites.
|
|
53
|
+
* 4. pre-normalized account-row `displayName`.
|
|
54
|
+
* 5. `username`
|
|
55
|
+
* 6. `Account 0x12345678…` (derived from publicKey, when present)
|
|
56
|
+
* 7. Translated fallback (e.g. "Unnamed")
|
|
55
57
|
*
|
|
56
58
|
* The translation key `common.unnamed` is used for the final fallback. If the
|
|
57
59
|
* caller does not pass a locale, the default English translation is used.
|
|
@@ -79,6 +81,7 @@ export declare const buildAccountsArray: (accounts: Record<string, QuickAccount>
|
|
|
79
81
|
*/
|
|
80
82
|
export declare const createQuickAccount: (sessionId: string, userData: {
|
|
81
83
|
name?: string | {
|
|
84
|
+
displayName?: string;
|
|
82
85
|
full?: string;
|
|
83
86
|
first?: string;
|
|
84
87
|
last?: string;
|
|
@@ -89,7 +92,7 @@ export declare const createQuickAccount: (sessionId: string, userData: {
|
|
|
89
92
|
_id?: {
|
|
90
93
|
toString(): string;
|
|
91
94
|
} | string;
|
|
92
|
-
avatar?: string;
|
|
95
|
+
avatar?: string | null;
|
|
93
96
|
}, existingAccount?: QuickAccount, getFileDownloadUrl?: (fileId: string, variant: string) => string) => QuickAccount;
|
|
94
97
|
/**
|
|
95
98
|
* Merge a fresh `/auth/refresh-all` snapshot into an existing QuickAccount
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@oxyhq/core",
|
|
3
|
-
"version": "3.4.
|
|
3
|
+
"version": "3.4.17",
|
|
4
4
|
"description": "OxyHQ SDK Foundation — API client, authentication, cryptographic identity, and shared utilities",
|
|
5
5
|
"main": "dist/cjs/index.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -97,7 +97,7 @@
|
|
|
97
97
|
}
|
|
98
98
|
},
|
|
99
99
|
"dependencies": {
|
|
100
|
-
"@oxyhq/contracts": "^0.1.
|
|
100
|
+
"@oxyhq/contracts": "^0.1.1",
|
|
101
101
|
"bip39": "^3.1.0",
|
|
102
102
|
"buffer": "^6.0.3",
|
|
103
103
|
"elliptic": "^6.6.1",
|
package/src/AuthManager.ts
CHANGED
|
@@ -497,7 +497,7 @@ export class AuthManager {
|
|
|
497
497
|
this.oxyServices.httpService.setTokens(session.accessToken);
|
|
498
498
|
}
|
|
499
499
|
|
|
500
|
-
if (session.user && typeof
|
|
500
|
+
if (session.user && typeof session.user.id === 'string' && session.user.id.length > 0) {
|
|
501
501
|
this.currentUser = session.user;
|
|
502
502
|
}
|
|
503
503
|
|
|
@@ -514,6 +514,7 @@ export class AuthManager {
|
|
|
514
514
|
user: {
|
|
515
515
|
id: session.user.id,
|
|
516
516
|
username: session.user.username,
|
|
517
|
+
name: session.user.name,
|
|
517
518
|
avatar: session.user.avatar ?? null,
|
|
518
519
|
},
|
|
519
520
|
accessToken: session.accessToken,
|
|
@@ -758,6 +759,7 @@ export class AuthManager {
|
|
|
758
759
|
return {
|
|
759
760
|
id: account.user.id,
|
|
760
761
|
username: account.user.username,
|
|
762
|
+
name: account.user.name,
|
|
761
763
|
avatar: account.user.avatar ?? undefined,
|
|
762
764
|
};
|
|
763
765
|
}
|
|
@@ -806,6 +808,7 @@ export class AuthManager {
|
|
|
806
808
|
this.currentUser = {
|
|
807
809
|
id: hydrated.id,
|
|
808
810
|
username: hydrated.username,
|
|
811
|
+
name: hydrated.name,
|
|
809
812
|
avatar: hydrated.avatar ?? undefined,
|
|
810
813
|
};
|
|
811
814
|
this.notifyListeners();
|
|
@@ -1022,6 +1025,7 @@ export class AuthManager {
|
|
|
1022
1025
|
? {
|
|
1023
1026
|
id: updated.user.id,
|
|
1024
1027
|
username: updated.user.username,
|
|
1028
|
+
name: updated.user.name,
|
|
1025
1029
|
avatar: updated.user.avatar ?? undefined,
|
|
1026
1030
|
}
|
|
1027
1031
|
: null;
|
|
@@ -1083,6 +1087,7 @@ export class AuthManager {
|
|
|
1083
1087
|
? {
|
|
1084
1088
|
id: next.user.id,
|
|
1085
1089
|
username: next.user.username,
|
|
1090
|
+
name: next.user.name,
|
|
1086
1091
|
avatar: next.user.avatar ?? undefined,
|
|
1087
1092
|
}
|
|
1088
1093
|
: null;
|
|
@@ -684,7 +684,7 @@ export function OxyServicesAuthMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
684
684
|
continue;
|
|
685
685
|
}
|
|
686
686
|
const userId = e.user.id ?? e.user._id;
|
|
687
|
-
if (!userId || !e.user.username) {
|
|
687
|
+
if (!userId || !e.user.username || !e.user.name?.displayName) {
|
|
688
688
|
continue;
|
|
689
689
|
}
|
|
690
690
|
if (typeof e.authuser !== 'number') {
|
|
@@ -25,6 +25,7 @@
|
|
|
25
25
|
|
|
26
26
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
27
27
|
import type { SessionLoginResponse, MinimalUserData } from '../models/session';
|
|
28
|
+
import type { UserNameResponse } from '@oxyhq/contracts';
|
|
28
29
|
import { createDebugLogger } from '../shared/utils/debugUtils';
|
|
29
30
|
|
|
30
31
|
const debug = createDebugLogger('SSO');
|
|
@@ -40,6 +41,7 @@ interface SsoExchangeWireResponse {
|
|
|
40
41
|
id?: string;
|
|
41
42
|
_id?: string;
|
|
42
43
|
username?: string;
|
|
44
|
+
name?: UserNameResponse;
|
|
43
45
|
avatar?: string;
|
|
44
46
|
};
|
|
45
47
|
expiresAt?: string;
|
|
@@ -140,13 +142,14 @@ export function OxyServicesSsoMixin<T extends typeof OxyServicesBase>(Base: T) {
|
|
|
140
142
|
}
|
|
141
143
|
|
|
142
144
|
const userId = payload.user?.id ?? payload.user?._id;
|
|
143
|
-
if (!userId || typeof payload.user?.username !== 'string') {
|
|
145
|
+
if (!userId || typeof payload.user?.username !== 'string' || typeof payload.user.name?.displayName !== 'string') {
|
|
144
146
|
throw this.handleError(new Error('SSO exchange returned an invalid user'));
|
|
145
147
|
}
|
|
146
148
|
|
|
147
149
|
const user: MinimalUserData = {
|
|
148
150
|
id: userId,
|
|
149
151
|
username: payload.user.username,
|
|
152
|
+
name: payload.user.name,
|
|
150
153
|
avatar: payload.user.avatar,
|
|
151
154
|
};
|
|
152
155
|
|
|
@@ -10,6 +10,7 @@ import type {
|
|
|
10
10
|
PaginationInfo,
|
|
11
11
|
PrivacySettings,
|
|
12
12
|
} from '../models/interfaces';
|
|
13
|
+
import type { UserNameResponse, UserProfileUpdate } from '@oxyhq/contracts';
|
|
13
14
|
import type { OxyServicesBase } from '../OxyServices.base';
|
|
14
15
|
import { buildSearchParams, buildPaginationParams, type PaginationParams } from '../utils/apiUtils';
|
|
15
16
|
import { KeyManager } from '../crypto/keyManager';
|
|
@@ -38,7 +39,7 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
38
39
|
|
|
39
40
|
/**
|
|
40
41
|
* Lightweight username lookup for login flows.
|
|
41
|
-
* Returns minimal public info: exists, color, avatar, displayName.
|
|
42
|
+
* Returns minimal public info: exists, color, avatar, name.displayName.
|
|
42
43
|
* Faster than getProfileByUsername — no stats, no formatting.
|
|
43
44
|
*/
|
|
44
45
|
async lookupUsername(username: string): Promise<{
|
|
@@ -46,7 +47,7 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
46
47
|
username: string;
|
|
47
48
|
color: string | null;
|
|
48
49
|
avatar: string | null;
|
|
49
|
-
|
|
50
|
+
name: UserNameResponse;
|
|
50
51
|
}> {
|
|
51
52
|
return await this.makeRequest('GET', `/auth/lookup/${encodeURIComponent(username)}`, undefined, {
|
|
52
53
|
cache: true,
|
|
@@ -150,7 +151,7 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
150
151
|
}): Promise<Array<{
|
|
151
152
|
id: string;
|
|
152
153
|
username: string;
|
|
153
|
-
name
|
|
154
|
+
name: UserNameResponse;
|
|
154
155
|
description?: string;
|
|
155
156
|
isFederated?: boolean;
|
|
156
157
|
isAgent?: boolean;
|
|
@@ -225,7 +226,7 @@ export function OxyServicesUserMixin<T extends typeof OxyServicesBase>(Base: T)
|
|
|
225
226
|
*
|
|
226
227
|
* TanStack Query handles offline queuing automatically.
|
|
227
228
|
*/
|
|
228
|
-
async updateProfile(updates:
|
|
229
|
+
async updateProfile(updates: UserProfileUpdate): Promise<User> {
|
|
229
230
|
try {
|
|
230
231
|
const result = normalizeUserIdentity(
|
|
231
232
|
await this.makeRequest<User>('PUT', '/users/me', updates, { cache: false }),
|
package/src/models/interfaces.ts
CHANGED
|
@@ -87,32 +87,31 @@ export interface User {
|
|
|
87
87
|
id: string;
|
|
88
88
|
publicKey: string;
|
|
89
89
|
username: string;
|
|
90
|
-
/** Canonical display name resolved by the API. */
|
|
91
|
-
displayName: string;
|
|
92
90
|
email?: string;
|
|
93
91
|
// Avatar file id (asset id)
|
|
94
|
-
avatar?: string;
|
|
92
|
+
avatar?: string | null;
|
|
95
93
|
// Named color preset (e.g. 'teal', 'blue', 'purple')
|
|
96
|
-
color?: string;
|
|
94
|
+
color?: string | null;
|
|
97
95
|
// Privacy and security settings
|
|
98
96
|
privacySettings?: PrivacySettings;
|
|
99
97
|
/**
|
|
100
|
-
* Structured human name.
|
|
101
|
-
*
|
|
102
|
-
*
|
|
103
|
-
* `@oxyhq/contracts` — do NOT re-declare a bare `string` here.
|
|
98
|
+
* Structured human name. `name.displayName` is the canonical display string
|
|
99
|
+
* resolved by the API; consumers render it directly instead of recomposing
|
|
100
|
+
* names from `first` / `last` / `full` / `username`.
|
|
104
101
|
*/
|
|
105
|
-
name
|
|
102
|
+
name: UserNameResponse;
|
|
106
103
|
bio?: string;
|
|
107
104
|
location?: string;
|
|
108
105
|
website?: string;
|
|
109
106
|
createdAt?: string;
|
|
110
107
|
updatedAt?: string;
|
|
111
|
-
links?:
|
|
108
|
+
links?: string[];
|
|
109
|
+
linksMetadata?: Array<{
|
|
110
|
+
url: string;
|
|
112
111
|
title?: string;
|
|
113
112
|
description?: string;
|
|
114
113
|
image?: string;
|
|
115
|
-
|
|
114
|
+
id?: string;
|
|
116
115
|
}>;
|
|
117
116
|
// Social counts
|
|
118
117
|
_count?: {
|
|
@@ -653,7 +652,7 @@ export interface RefreshAllAccountUser {
|
|
|
653
652
|
* string. The server projects `name` verbatim from the user document. The
|
|
654
653
|
* single source of truth is `@oxyhq/contracts`.
|
|
655
654
|
*/
|
|
656
|
-
name
|
|
655
|
+
name: UserNameResponse;
|
|
657
656
|
avatar?: string | null;
|
|
658
657
|
email?: string;
|
|
659
658
|
color?: string | null;
|
package/src/models/session.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import type { UserNameResponse } from '@oxyhq/contracts';
|
|
2
|
+
|
|
1
3
|
export interface ClientSession {
|
|
2
4
|
sessionId: string;
|
|
3
5
|
deviceId: string;
|
|
@@ -23,6 +25,7 @@ export interface StorageKeys {
|
|
|
23
25
|
export interface MinimalUserData {
|
|
24
26
|
id: string;
|
|
25
27
|
username: string;
|
|
28
|
+
name: UserNameResponse;
|
|
26
29
|
avatar?: string; // file id
|
|
27
30
|
}
|
|
28
31
|
|
|
@@ -5,11 +5,10 @@ import {
|
|
|
5
5
|
} from '../accountUtils';
|
|
6
6
|
|
|
7
7
|
describe('getAccountDisplayName', () => {
|
|
8
|
-
it('prefers the API displayName when present', () => {
|
|
8
|
+
it('prefers the API name.displayName when present', () => {
|
|
9
9
|
expect(
|
|
10
10
|
getAccountDisplayName({
|
|
11
|
-
name: { first: 'Nate' },
|
|
12
|
-
displayName: 'Nate Isern',
|
|
11
|
+
name: { first: 'Nate', displayName: 'Nate Isern' },
|
|
13
12
|
username: 'nateus',
|
|
14
13
|
}),
|
|
15
14
|
).toBe('Nate Isern');
|
|
@@ -51,7 +50,7 @@ describe('getAccountDisplayName', () => {
|
|
|
51
50
|
).toBe('Nathaniel Isern');
|
|
52
51
|
});
|
|
53
52
|
|
|
54
|
-
it('uses displayName when there is no structured name', () => {
|
|
53
|
+
it('uses pre-normalized account-row displayName when there is no structured name', () => {
|
|
55
54
|
expect(
|
|
56
55
|
getAccountDisplayName({
|
|
57
56
|
displayName: 'Cool Display',
|
|
@@ -30,8 +30,14 @@ export interface QuickAccount {
|
|
|
30
30
|
|
|
31
31
|
/** Minimal user shape accepted by display-name helpers. Avoids importing the full User type. */
|
|
32
32
|
export interface DisplayNameUserShape {
|
|
33
|
-
name?: string | {
|
|
34
|
-
|
|
33
|
+
name?: string | {
|
|
34
|
+
displayName?: string;
|
|
35
|
+
first?: string;
|
|
36
|
+
last?: string;
|
|
37
|
+
full?: string;
|
|
38
|
+
[key: string]: unknown;
|
|
39
|
+
};
|
|
40
|
+
/** Pre-normalized account-row display name, not the API User DTO field. */
|
|
35
41
|
displayName?: string;
|
|
36
42
|
username?: string;
|
|
37
43
|
publicKey?: string;
|
|
@@ -51,12 +57,13 @@ export const formatPublicKeyHandle = (publicKey: string): string => {
|
|
|
51
57
|
* Resolve a friendly display name for a user.
|
|
52
58
|
*
|
|
53
59
|
* Order of preference:
|
|
54
|
-
* 1. `displayName` from the API contract.
|
|
60
|
+
* 1. `name.displayName` from the API user contract.
|
|
55
61
|
* 2. `name.full`, or composed `name.first name.last` for local unsaved shapes.
|
|
56
|
-
* 3. `name` when
|
|
57
|
-
* 4. `
|
|
58
|
-
* 5. `
|
|
59
|
-
* 6.
|
|
62
|
+
* 3. `name` when passed as a plain string by local non-DTO call sites.
|
|
63
|
+
* 4. pre-normalized account-row `displayName`.
|
|
64
|
+
* 5. `username`
|
|
65
|
+
* 6. `Account 0x12345678…` (derived from publicKey, when present)
|
|
66
|
+
* 7. Translated fallback (e.g. "Unnamed")
|
|
60
67
|
*
|
|
61
68
|
* The translation key `common.unnamed` is used for the final fallback. If the
|
|
62
69
|
* caller does not pass a locale, the default English translation is used.
|
|
@@ -69,9 +76,10 @@ export const getAccountDisplayName = (
|
|
|
69
76
|
|
|
70
77
|
const { name, displayName, username, publicKey } = user;
|
|
71
78
|
|
|
72
|
-
if (typeof displayName === 'string' && displayName.trim()) return displayName.trim();
|
|
73
|
-
|
|
74
79
|
if (name && typeof name === 'object') {
|
|
80
|
+
if (typeof name.displayName === 'string' && name.displayName.trim()) {
|
|
81
|
+
return name.displayName.trim();
|
|
82
|
+
}
|
|
75
83
|
if (typeof name.full === 'string' && name.full.trim()) return name.full.trim();
|
|
76
84
|
const first = typeof name.first === 'string' ? name.first.trim() : '';
|
|
77
85
|
const last = typeof name.last === 'string' ? name.last.trim() : '';
|
|
@@ -81,6 +89,8 @@ export const getAccountDisplayName = (
|
|
|
81
89
|
return name.trim();
|
|
82
90
|
}
|
|
83
91
|
|
|
92
|
+
if (typeof displayName === 'string' && displayName.trim()) return displayName.trim();
|
|
93
|
+
|
|
84
94
|
if (typeof username === 'string' && username.trim()) return username.trim();
|
|
85
95
|
|
|
86
96
|
if (typeof publicKey === 'string' && publicKey.length > 0) {
|
|
@@ -136,12 +146,12 @@ export const buildAccountsArray = (
|
|
|
136
146
|
export const createQuickAccount = (
|
|
137
147
|
sessionId: string,
|
|
138
148
|
userData: {
|
|
139
|
-
name?: string | { full?: string; first?: string; last?: string };
|
|
149
|
+
name?: string | { displayName?: string; full?: string; first?: string; last?: string };
|
|
140
150
|
username?: string;
|
|
141
151
|
publicKey?: string;
|
|
142
152
|
id?: string;
|
|
143
153
|
_id?: { toString(): string } | string;
|
|
144
|
-
avatar?: string;
|
|
154
|
+
avatar?: string | null;
|
|
145
155
|
},
|
|
146
156
|
existingAccount?: QuickAccount,
|
|
147
157
|
getFileDownloadUrl?: (fileId: string, variant: string) => string
|
|
@@ -151,10 +161,11 @@ export const createQuickAccount = (
|
|
|
151
161
|
|
|
152
162
|
// Preserve existing avatarUrl if avatar hasn't changed (prevents image reload)
|
|
153
163
|
let avatarUrl: string | undefined;
|
|
154
|
-
|
|
164
|
+
const avatar = userData.avatar ?? undefined;
|
|
165
|
+
if (existingAccount && existingAccount.avatar === avatar && existingAccount.avatarUrl) {
|
|
155
166
|
avatarUrl = existingAccount.avatarUrl;
|
|
156
|
-
} else if (
|
|
157
|
-
avatarUrl = getFileDownloadUrl(
|
|
167
|
+
} else if (avatar && getFileDownloadUrl) {
|
|
168
|
+
avatarUrl = getFileDownloadUrl(avatar, 'thumb');
|
|
158
169
|
}
|
|
159
170
|
|
|
160
171
|
return {
|
|
@@ -162,7 +173,7 @@ export const createQuickAccount = (
|
|
|
162
173
|
userId,
|
|
163
174
|
username: userData.username || '',
|
|
164
175
|
displayName,
|
|
165
|
-
avatar
|
|
176
|
+
avatar,
|
|
166
177
|
avatarUrl,
|
|
167
178
|
};
|
|
168
179
|
};
|