@lark-apaas/client-toolkit 1.1.14-alpha.devServer.1 → 1.1.15-alpha.dev.1
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/lib/components/User/UserDisplay.d.ts +6 -1
- package/lib/components/User/UserDisplay.js +80 -29
- package/lib/components/User/UserSelect.d.ts +7 -3
- package/lib/components/User/UserSelect.js +134 -5
- package/lib/components/User/UserWithAvatar.js +6 -1
- package/lib/logger/intercept-global-error.js +10 -9
- package/lib/logger/log-types.d.ts +13 -4
- package/lib/logger/log-types.js +5 -2
- package/lib/logger/selected-logs.js +51 -5
- package/package.json +1 -1
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import type { IUserProfile } from '../../apis/udt-types';
|
|
3
3
|
export interface UserDisplayProps {
|
|
4
|
-
|
|
4
|
+
/**
|
|
5
|
+
* 支持传入完整的用户资料(IUserProfile)/ 列表(IUserProfile[])
|
|
6
|
+
* 或仅传入用户 ID(string)/ 列表(string[])。
|
|
7
|
+
* 当传入 user_id 或 user_id[] 时组件会自动拉取用户资料并渲染。
|
|
8
|
+
*/
|
|
9
|
+
users: IUserProfile | IUserProfile[] | string | string[];
|
|
5
10
|
size?: 'small' | 'medium' | 'large';
|
|
6
11
|
className?: string;
|
|
7
12
|
style?: React.CSSProperties;
|
|
@@ -6,38 +6,82 @@ import { UserProfile } from "./UserProfile/index.js";
|
|
|
6
6
|
import { UserWithAvatar } from "./UserWithAvatar.js";
|
|
7
7
|
import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover.js";
|
|
8
8
|
const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
9
|
+
const normalizedIds = useMemo(()=>{
|
|
10
|
+
if (!users) return [];
|
|
11
|
+
if (Array.isArray(users)) {
|
|
12
|
+
if (0 === users.length) return [];
|
|
13
|
+
const first = users[0];
|
|
14
|
+
const isStringArray = 'string' == typeof first;
|
|
15
|
+
return isStringArray ? users.filter(Boolean).map((id)=>String(id)) : users.map((u)=>String(u.user_id)).filter(Boolean);
|
|
16
|
+
}
|
|
17
|
+
return 'string' == typeof users ? [
|
|
18
|
+
String(users)
|
|
19
|
+
] : [
|
|
20
|
+
String(users.user_id)
|
|
21
|
+
].filter(Boolean);
|
|
22
|
+
}, [
|
|
23
|
+
users
|
|
24
|
+
]);
|
|
25
|
+
const inputProfilesMap = useMemo(()=>{
|
|
26
|
+
const map = new Map();
|
|
27
|
+
if (!users) return map;
|
|
28
|
+
if (Array.isArray(users)) {
|
|
29
|
+
const first = users[0];
|
|
30
|
+
const isStringArray = 'string' == typeof first;
|
|
31
|
+
if (!isStringArray) {
|
|
32
|
+
for (const u of users)if (u?.user_id) map.set(String(u.user_id), {
|
|
33
|
+
user_id: String(u.user_id),
|
|
34
|
+
name: u?.name ?? '',
|
|
35
|
+
avatar: u?.avatar ?? '',
|
|
36
|
+
email: u?.email ?? '',
|
|
37
|
+
status: u?.status ?? 1
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
} else if ('string' != typeof users) {
|
|
41
|
+
const u = users;
|
|
42
|
+
if (u?.user_id) map.set(String(u.user_id), {
|
|
43
|
+
user_id: String(u.user_id),
|
|
44
|
+
name: u?.name ?? '',
|
|
45
|
+
avatar: u?.avatar ?? '',
|
|
46
|
+
email: u?.email ?? '',
|
|
47
|
+
status: u?.status ?? 1
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return map;
|
|
51
|
+
}, [
|
|
12
52
|
users
|
|
13
53
|
]);
|
|
14
|
-
const [resolvedUsers, setResolvedUsers] = useState(
|
|
54
|
+
const [resolvedUsers, setResolvedUsers] = useState(()=>normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
|
|
55
|
+
user_id: id,
|
|
56
|
+
name: '',
|
|
57
|
+
avatar: '',
|
|
58
|
+
email: '',
|
|
59
|
+
status: 1
|
|
60
|
+
}));
|
|
15
61
|
const [loadingProfiles, setLoadingProfiles] = useState(false);
|
|
16
62
|
useEffect(()=>{
|
|
17
63
|
let isCancelled = false;
|
|
18
|
-
if (!
|
|
64
|
+
if (!normalizedIds.length) {
|
|
19
65
|
setResolvedUsers([]);
|
|
20
66
|
setLoadingProfiles(false);
|
|
21
67
|
return ()=>{
|
|
22
68
|
isCancelled = true;
|
|
23
69
|
};
|
|
24
70
|
}
|
|
25
|
-
const usersNeedingDetails = normalizedUsers.filter((user)=>!user?.name?.trim());
|
|
26
|
-
if (!usersNeedingDetails.length) {
|
|
27
|
-
setResolvedUsers(normalizedUsers);
|
|
28
|
-
setLoadingProfiles(false);
|
|
29
|
-
return ()=>{
|
|
30
|
-
isCancelled = true;
|
|
31
|
-
};
|
|
32
|
-
}
|
|
33
71
|
const fetchProfiles = async ()=>{
|
|
34
72
|
try {
|
|
35
73
|
setLoadingProfiles(true);
|
|
36
74
|
const dataloom = await getDataloom();
|
|
37
75
|
if (!dataloom) throw new Error('dataloom client is unavailable');
|
|
38
|
-
const ids =
|
|
76
|
+
const ids = normalizedIds.map((id)=>Number(id)).filter((id)=>Number.isFinite(id));
|
|
39
77
|
if (!ids.length) {
|
|
40
|
-
setResolvedUsers(
|
|
78
|
+
setResolvedUsers(normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
|
|
79
|
+
user_id: id,
|
|
80
|
+
name: '',
|
|
81
|
+
avatar: '',
|
|
82
|
+
email: '',
|
|
83
|
+
status: 1
|
|
84
|
+
}));
|
|
41
85
|
setLoadingProfiles(false);
|
|
42
86
|
return;
|
|
43
87
|
}
|
|
@@ -51,28 +95,35 @@ const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
|
|
|
51
95
|
user_id: id,
|
|
52
96
|
name: profile?.name ?? '',
|
|
53
97
|
avatar: profile?.avatar ?? '',
|
|
54
|
-
email: profile?.email,
|
|
55
|
-
status: profile?.status
|
|
56
|
-
...profile
|
|
98
|
+
email: profile?.email ?? '',
|
|
99
|
+
status: profile?.status ?? 1
|
|
57
100
|
});
|
|
58
101
|
});
|
|
59
|
-
const mergedUsers =
|
|
60
|
-
const id = String(user.user_id);
|
|
102
|
+
const mergedUsers = normalizedIds.map((id)=>{
|
|
61
103
|
const fetched = fetchedMap.get(id);
|
|
62
|
-
|
|
104
|
+
const given = inputProfilesMap.get(id);
|
|
105
|
+
const name = given?.name?.trim() ? given.name : fetched?.name ?? '';
|
|
106
|
+
const avatar = given?.avatar || fetched?.avatar || '';
|
|
107
|
+
const email = given?.email || fetched?.email || '';
|
|
108
|
+
const status = given?.status ?? fetched?.status ?? 1;
|
|
63
109
|
return {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
status: user.status ?? fetched.status
|
|
110
|
+
user_id: id,
|
|
111
|
+
name,
|
|
112
|
+
avatar,
|
|
113
|
+
email,
|
|
114
|
+
status
|
|
70
115
|
};
|
|
71
116
|
});
|
|
72
117
|
if (!isCancelled) setResolvedUsers(mergedUsers);
|
|
73
118
|
} catch (error) {
|
|
74
119
|
console.error('Failed to resolve user profiles:', error);
|
|
75
|
-
if (!isCancelled) setResolvedUsers(
|
|
120
|
+
if (!isCancelled) setResolvedUsers(normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
|
|
121
|
+
user_id: id,
|
|
122
|
+
name: '',
|
|
123
|
+
avatar: '',
|
|
124
|
+
email: '',
|
|
125
|
+
status: 1
|
|
126
|
+
}));
|
|
76
127
|
} finally{
|
|
77
128
|
if (!isCancelled) setLoadingProfiles(false);
|
|
78
129
|
}
|
|
@@ -82,7 +133,7 @@ const UserDisplay = ({ users, size, className, style, showLabel = true })=>{
|
|
|
82
133
|
isCancelled = true;
|
|
83
134
|
};
|
|
84
135
|
}, [
|
|
85
|
-
|
|
136
|
+
normalizedIds
|
|
86
137
|
]);
|
|
87
138
|
if (!resolvedUsers.length || loadingProfiles) return null;
|
|
88
139
|
return /*#__PURE__*/ jsx("div", {
|
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
import React from 'react';
|
|
2
2
|
import type { IUserProfile } from '../../apis/udt-types';
|
|
3
3
|
export interface UserSelectProps {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
/**
|
|
5
|
+
* 支持传入完整的用户资料(IUserProfile)/ 列表(IUserProfile[])
|
|
6
|
+
* 或仅传入用户 ID(string)/ 列表(string[])。
|
|
7
|
+
*/
|
|
8
|
+
value?: IUserProfile | IUserProfile[] | string | string[];
|
|
9
|
+
onChange?: (value: IUserProfile | IUserProfile[] | undefined) => void;
|
|
10
|
+
defaultValue?: IUserProfile | IUserProfile[] | string | string[];
|
|
7
11
|
mode?: 'single' | 'multiple';
|
|
8
12
|
placeholder?: string;
|
|
9
13
|
fetchUsers?: (keyword: string) => Promise<IUserProfile[]>;
|
|
@@ -3,6 +3,127 @@ import react from "react";
|
|
|
3
3
|
import { getDataloom } from "../../integrations/dataloom.js";
|
|
4
4
|
import { UserSelectUI } from "./UserSelectUI/index.js";
|
|
5
5
|
const UserSelect = ({ mode = 'single', defaultValue, value, onChange, placeholder, fetchUsers })=>{
|
|
6
|
+
const normalizedIds = react.useMemo(()=>{
|
|
7
|
+
const src = value ?? defaultValue;
|
|
8
|
+
if (!src) return [];
|
|
9
|
+
if (Array.isArray(src)) {
|
|
10
|
+
if (0 === src.length) return [];
|
|
11
|
+
const first = src[0];
|
|
12
|
+
const isStringArray = 'string' == typeof first;
|
|
13
|
+
return isStringArray ? src.filter(Boolean).map((id)=>String(id)) : src.map((u)=>String(u.user_id)).filter(Boolean);
|
|
14
|
+
}
|
|
15
|
+
return 'string' == typeof src ? [
|
|
16
|
+
String(src)
|
|
17
|
+
] : [
|
|
18
|
+
String(src.user_id)
|
|
19
|
+
].filter(Boolean);
|
|
20
|
+
}, [
|
|
21
|
+
value,
|
|
22
|
+
defaultValue
|
|
23
|
+
]);
|
|
24
|
+
const inputProfilesMap = react.useMemo(()=>{
|
|
25
|
+
const map = new Map();
|
|
26
|
+
const src = value ?? defaultValue;
|
|
27
|
+
if (!src) return map;
|
|
28
|
+
if (Array.isArray(src)) {
|
|
29
|
+
const first = src[0];
|
|
30
|
+
const isStringArray = 'string' == typeof first;
|
|
31
|
+
if (!isStringArray) {
|
|
32
|
+
for (const u of src)if (u?.user_id) map.set(String(u.user_id), {
|
|
33
|
+
user_id: String(u.user_id),
|
|
34
|
+
name: u?.name ?? '',
|
|
35
|
+
avatar: u?.avatar ?? '',
|
|
36
|
+
email: u?.email ?? '',
|
|
37
|
+
status: u?.status ?? 1
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
} else if ('string' != typeof src) {
|
|
41
|
+
const u = src;
|
|
42
|
+
if (u?.user_id) map.set(String(u.user_id), {
|
|
43
|
+
user_id: String(u.user_id),
|
|
44
|
+
name: u?.name ?? '',
|
|
45
|
+
avatar: u?.avatar ?? '',
|
|
46
|
+
email: u?.email ?? '',
|
|
47
|
+
status: u?.status ?? 1
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
return map;
|
|
51
|
+
}, [
|
|
52
|
+
value,
|
|
53
|
+
defaultValue
|
|
54
|
+
]);
|
|
55
|
+
const [uiValue, setUiValue] = react.useState(()=>{
|
|
56
|
+
if (!normalizedIds.length) return;
|
|
57
|
+
const profiles = normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
|
|
58
|
+
user_id: id,
|
|
59
|
+
name: '',
|
|
60
|
+
avatar: '',
|
|
61
|
+
email: '',
|
|
62
|
+
status: 1
|
|
63
|
+
});
|
|
64
|
+
return 'single' === mode ? profiles[0] : profiles;
|
|
65
|
+
});
|
|
66
|
+
react.useEffect(()=>{
|
|
67
|
+
if (!normalizedIds.length) return void setUiValue(void 0);
|
|
68
|
+
const fetchProfiles = async ()=>{
|
|
69
|
+
try {
|
|
70
|
+
const ids = normalizedIds.map((id)=>Number(id)).filter((id)=>Number.isFinite(id));
|
|
71
|
+
if (!ids.length) {
|
|
72
|
+
const profiles = normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
|
|
73
|
+
user_id: id,
|
|
74
|
+
name: '',
|
|
75
|
+
avatar: '',
|
|
76
|
+
email: '',
|
|
77
|
+
status: 1
|
|
78
|
+
});
|
|
79
|
+
setUiValue('single' === mode ? profiles[0] : profiles);
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
const dataloom = await getDataloom();
|
|
83
|
+
const response = await dataloom.service.user.getByIds(ids);
|
|
84
|
+
const fetchedList = Array.isArray(response?.data) ? response?.data : Array.isArray(response?.data?.user_list) ? response?.data?.user_list : [];
|
|
85
|
+
const fetchedMap = new Map();
|
|
86
|
+
fetchedList.forEach((profile)=>{
|
|
87
|
+
const id = String(profile?.user_id ?? '');
|
|
88
|
+
if (!id) return;
|
|
89
|
+
fetchedMap.set(id, {
|
|
90
|
+
user_id: id,
|
|
91
|
+
name: profile?.name ?? '',
|
|
92
|
+
avatar: profile?.avatar ?? '',
|
|
93
|
+
email: profile?.email ?? '',
|
|
94
|
+
status: profile?.status ?? 1
|
|
95
|
+
});
|
|
96
|
+
});
|
|
97
|
+
const merged = normalizedIds.map((id)=>{
|
|
98
|
+
const fetched = fetchedMap.get(id);
|
|
99
|
+
const given = inputProfilesMap.get(id);
|
|
100
|
+
return {
|
|
101
|
+
user_id: id,
|
|
102
|
+
name: given?.name?.trim() ? given.name : fetched?.name ?? '',
|
|
103
|
+
avatar: given?.avatar || fetched?.avatar || '',
|
|
104
|
+
email: given?.email || fetched?.email || '',
|
|
105
|
+
status: given?.status ?? fetched?.status ?? 1
|
|
106
|
+
};
|
|
107
|
+
});
|
|
108
|
+
setUiValue('single' === mode ? merged[0] : merged);
|
|
109
|
+
} catch (error) {
|
|
110
|
+
console.error('Failed to resolve select value profiles:', error);
|
|
111
|
+
const profiles = normalizedIds.map((id)=>inputProfilesMap.get(id) ?? {
|
|
112
|
+
user_id: id,
|
|
113
|
+
name: '',
|
|
114
|
+
avatar: '',
|
|
115
|
+
email: '',
|
|
116
|
+
status: 1
|
|
117
|
+
});
|
|
118
|
+
setUiValue('single' === mode ? profiles[0] : profiles);
|
|
119
|
+
}
|
|
120
|
+
};
|
|
121
|
+
fetchProfiles();
|
|
122
|
+
}, [
|
|
123
|
+
normalizedIds,
|
|
124
|
+
inputProfilesMap,
|
|
125
|
+
mode
|
|
126
|
+
]);
|
|
6
127
|
const fetchUsersImpl = react.useCallback(async (search)=>{
|
|
7
128
|
if (fetchUsers) return fetchUsers(search);
|
|
8
129
|
try {
|
|
@@ -30,15 +151,23 @@ const UserSelect = ({ mode = 'single', defaultValue, value, onChange, placeholde
|
|
|
30
151
|
return /*#__PURE__*/ jsx("div", {
|
|
31
152
|
className: "user-select-container",
|
|
32
153
|
children: /*#__PURE__*/ jsx(UserSelectUI, {
|
|
33
|
-
defaultValue:
|
|
154
|
+
defaultValue: void 0,
|
|
34
155
|
mode: selectMode,
|
|
35
156
|
onSearch: fetchUsersImpl,
|
|
36
157
|
allowClear: true,
|
|
37
158
|
placeholder: placeholder,
|
|
38
|
-
value:
|
|
39
|
-
onChange: (
|
|
40
|
-
if (
|
|
41
|
-
|
|
159
|
+
value: uiValue,
|
|
160
|
+
onChange: (next)=>{
|
|
161
|
+
if (!onChange) return;
|
|
162
|
+
if ('multiple' === selectMode) {
|
|
163
|
+
const arr = Array.isArray(next) ? next ?? [] : next ? [
|
|
164
|
+
next
|
|
165
|
+
] : [];
|
|
166
|
+
onChange(arr);
|
|
167
|
+
} else {
|
|
168
|
+
const single = Array.isArray(next) ? next[0] ?? void 0 : next ?? void 0;
|
|
169
|
+
onChange(single);
|
|
170
|
+
}
|
|
42
171
|
}
|
|
43
172
|
})
|
|
44
173
|
});
|
|
@@ -18,6 +18,11 @@ const sizeClassMap = {
|
|
|
18
18
|
medium: 'py-0.5 pl-0.5 pr-2 max-w-[172px]',
|
|
19
19
|
large: 'py-1 pl-1 pr-2.5 max-w-[196px]'
|
|
20
20
|
};
|
|
21
|
+
const sizeClassMapWithoutLabel = {
|
|
22
|
+
small: 'py-0.5 px-0.5 max-w-[148px]',
|
|
23
|
+
medium: 'py-0.5 px-0.5 max-w-[172px]',
|
|
24
|
+
large: 'py-1 px-1 max-w-[196px]'
|
|
25
|
+
};
|
|
21
26
|
const textVariantMap = {
|
|
22
27
|
small: 'text-[12px] leading-[16px]',
|
|
23
28
|
medium: 'text-[14px] leading-[20px]',
|
|
@@ -32,7 +37,7 @@ function UserWithAvatar({ data, size = 'medium', mode = 'tag', className, showLa
|
|
|
32
37
|
'large'
|
|
33
38
|
].includes(size) ? size : 'medium';
|
|
34
39
|
return /*#__PURE__*/ jsxs("div", {
|
|
35
|
-
className: clsxWithTw('flex min-w-0 items-center gap-1 rounded-full', sizeClassMap[formatSize], {
|
|
40
|
+
className: clsxWithTw('flex min-w-0 items-center gap-1 rounded-full', showLabel ? sizeClassMap[formatSize] : sizeClassMapWithoutLabel[formatSize], {
|
|
36
41
|
'bg-muted': 'tag' === mode
|
|
37
42
|
}, className),
|
|
38
43
|
children: [
|
|
@@ -10,13 +10,6 @@ function processDevServerLog(log) {
|
|
|
10
10
|
devServerDisconnectInfo = {
|
|
11
11
|
time
|
|
12
12
|
};
|
|
13
|
-
submitSlardarEvent({
|
|
14
|
-
name: 'sandbox-devServer',
|
|
15
|
-
categories: {
|
|
16
|
-
type: 'disconnected',
|
|
17
|
-
time
|
|
18
|
-
}
|
|
19
|
-
});
|
|
20
13
|
submitPostMessage({
|
|
21
14
|
type: 'DevServerMessage',
|
|
22
15
|
data: {
|
|
@@ -24,6 +17,13 @@ function processDevServerLog(log) {
|
|
|
24
17
|
status: 'disconnected'
|
|
25
18
|
}
|
|
26
19
|
});
|
|
20
|
+
submitSlardarEvent({
|
|
21
|
+
name: 'sandbox-devServer',
|
|
22
|
+
categories: {
|
|
23
|
+
type: 'disconnected',
|
|
24
|
+
time
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
27
|
return;
|
|
28
28
|
}
|
|
29
29
|
if (!devServerDisconnectInfo) return;
|
|
@@ -76,11 +76,12 @@ function interceptErrors() {
|
|
|
76
76
|
const originalMethod = window.console[method];
|
|
77
77
|
window.console[method] = (...args)=>{
|
|
78
78
|
originalMethod(...args);
|
|
79
|
+
const level = 'log' === method ? 'info' : method;
|
|
79
80
|
const log = args[0];
|
|
80
81
|
if ('string' == typeof log) processDevServerLog(log);
|
|
81
|
-
if ('string' == typeof log && log.startsWith('[Dataloom]') && levelSchema.safeParse(
|
|
82
|
+
if ('string' == typeof log && log.startsWith('[Dataloom]') && levelSchema.safeParse(level).success) {
|
|
82
83
|
logger.log({
|
|
83
|
-
level:
|
|
84
|
+
level: level,
|
|
84
85
|
args
|
|
85
86
|
});
|
|
86
87
|
submitPostMessage({
|
|
@@ -28,10 +28,10 @@ export declare const logStackFrameSchema: z.ZodObject<{
|
|
|
28
28
|
}, z.core.$strip>;
|
|
29
29
|
export declare const levelSchema: z.ZodEnum<{
|
|
30
30
|
success: "success";
|
|
31
|
+
debug: "debug";
|
|
31
32
|
info: "info";
|
|
32
33
|
warn: "warn";
|
|
33
34
|
error: "error";
|
|
34
|
-
debug: "debug";
|
|
35
35
|
}>;
|
|
36
36
|
export declare const logMeta: z.ZodObject<{
|
|
37
37
|
stacktrace: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
@@ -45,15 +45,18 @@ export declare const logMeta: z.ZodObject<{
|
|
|
45
45
|
noStacktrace: z.ZodOptional<z.ZodBoolean>;
|
|
46
46
|
repairMessage: z.ZodOptional<z.ZodString>;
|
|
47
47
|
type: z.ZodOptional<z.ZodString>;
|
|
48
|
+
isDuplicate: z.ZodOptional<z.ZodBoolean>;
|
|
49
|
+
duplicateCount: z.ZodOptional<z.ZodNumber>;
|
|
50
|
+
duplicateOfId: z.ZodOptional<z.ZodString>;
|
|
48
51
|
}, z.core.$strip>;
|
|
49
52
|
export declare const selectedLogSchema: z.ZodObject<{
|
|
50
53
|
type: z.ZodLiteral<"typedLogV2">;
|
|
51
54
|
level: z.ZodEnum<{
|
|
52
55
|
success: "success";
|
|
56
|
+
debug: "debug";
|
|
53
57
|
info: "info";
|
|
54
58
|
warn: "warn";
|
|
55
59
|
error: "error";
|
|
56
|
-
debug: "debug";
|
|
57
60
|
}>;
|
|
58
61
|
id: z.ZodString;
|
|
59
62
|
args: z.ZodArray<z.ZodUnknown>;
|
|
@@ -69,16 +72,19 @@ export declare const selectedLogSchema: z.ZodObject<{
|
|
|
69
72
|
noStacktrace: z.ZodOptional<z.ZodBoolean>;
|
|
70
73
|
repairMessage: z.ZodOptional<z.ZodString>;
|
|
71
74
|
type: z.ZodOptional<z.ZodString>;
|
|
75
|
+
isDuplicate: z.ZodOptional<z.ZodBoolean>;
|
|
76
|
+
duplicateCount: z.ZodOptional<z.ZodNumber>;
|
|
77
|
+
duplicateOfId: z.ZodOptional<z.ZodString>;
|
|
72
78
|
}, z.core.$strip>;
|
|
73
79
|
}, z.core.$strip>;
|
|
74
|
-
export type LogLevel =
|
|
80
|
+
export type LogLevel = z.infer<typeof levelSchema>;
|
|
75
81
|
export declare const logWithMetaSchema: z.ZodObject<{
|
|
76
82
|
level: z.ZodEnum<{
|
|
77
83
|
success: "success";
|
|
84
|
+
debug: "debug";
|
|
78
85
|
info: "info";
|
|
79
86
|
warn: "warn";
|
|
80
87
|
error: "error";
|
|
81
|
-
debug: "debug";
|
|
82
88
|
}>;
|
|
83
89
|
args: z.ZodArray<z.ZodUnknown>;
|
|
84
90
|
meta: z.ZodOptional<z.ZodObject<{
|
|
@@ -93,6 +99,9 @@ export declare const logWithMetaSchema: z.ZodObject<{
|
|
|
93
99
|
noStacktrace: z.ZodOptional<z.ZodBoolean>;
|
|
94
100
|
repairMessage: z.ZodOptional<z.ZodString>;
|
|
95
101
|
type: z.ZodOptional<z.ZodString>;
|
|
102
|
+
isDuplicate: z.ZodOptional<z.ZodBoolean>;
|
|
103
|
+
duplicateCount: z.ZodOptional<z.ZodNumber>;
|
|
104
|
+
duplicateOfId: z.ZodOptional<z.ZodString>;
|
|
96
105
|
}, z.core.$strip>>;
|
|
97
106
|
}, z.core.$strip>;
|
|
98
107
|
export type LogStackFrame = z.infer<typeof logStackFrameSchema>;
|
package/lib/logger/log-types.js
CHANGED
|
@@ -27,10 +27,10 @@ const logStackFrameSchema = zod.object({
|
|
|
27
27
|
columnNumber: zod.number()
|
|
28
28
|
});
|
|
29
29
|
const levelSchema = zod["enum"]([
|
|
30
|
+
'debug',
|
|
30
31
|
'info',
|
|
31
32
|
'warn',
|
|
32
33
|
'error',
|
|
33
|
-
'debug',
|
|
34
34
|
'success'
|
|
35
35
|
]);
|
|
36
36
|
const logMeta = zod.object({
|
|
@@ -39,7 +39,10 @@ const logMeta = zod.object({
|
|
|
39
39
|
skipFrame: zod.optional(zod.number()),
|
|
40
40
|
noStacktrace: zod.optional(zod.boolean()),
|
|
41
41
|
repairMessage: zod.optional(zod.string()),
|
|
42
|
-
type: zod.optional(zod.string())
|
|
42
|
+
type: zod.optional(zod.string()),
|
|
43
|
+
isDuplicate: zod.optional(zod.boolean()),
|
|
44
|
+
duplicateCount: zod.optional(zod.number()),
|
|
45
|
+
duplicateOfId: zod.optional(zod.string())
|
|
43
46
|
});
|
|
44
47
|
const selectedLogSchema = zod.object({
|
|
45
48
|
type: zod.literal('typedLogV2'),
|
|
@@ -40,7 +40,17 @@ async function sendSelectedLog(logWithoutID) {
|
|
|
40
40
|
if (!log.meta.stacktrace) try {
|
|
41
41
|
const stacktrace = await stacktrace_js.fromError(error);
|
|
42
42
|
log.meta.stacktrace = mapStacktrace(stacktrace);
|
|
43
|
-
} catch (e) {
|
|
43
|
+
} catch (e) {
|
|
44
|
+
if (window.parent !== window) try {
|
|
45
|
+
window.parent.postMessage({
|
|
46
|
+
type: 'STACKTRACE_PARSE_ERROR',
|
|
47
|
+
payload: {
|
|
48
|
+
error: e instanceof Error ? e.message : String(e),
|
|
49
|
+
context: 'StackTrace.fromError'
|
|
50
|
+
}
|
|
51
|
+
}, '*');
|
|
52
|
+
} catch (postError) {}
|
|
53
|
+
}
|
|
44
54
|
newParts.push(newError.message, newError);
|
|
45
55
|
} else newParts.push(log.args[i]);
|
|
46
56
|
log.args = newParts;
|
|
@@ -49,11 +59,46 @@ async function sendSelectedLog(logWithoutID) {
|
|
|
49
59
|
const firstFrameIndex = frames.findIndex((frame)=>!frame.fileName.includes('node_modules/@lark-apaas/client-toolkit/lib/logger'));
|
|
50
60
|
frames = -1 === firstFrameIndex ? [] : frames.slice(firstFrameIndex);
|
|
51
61
|
log.meta.stacktrace = frames;
|
|
52
|
-
} catch (e) {
|
|
62
|
+
} catch (e) {
|
|
63
|
+
if (window.parent !== window) try {
|
|
64
|
+
window.parent.postMessage({
|
|
65
|
+
type: 'STACKTRACE_PARSE_ERROR',
|
|
66
|
+
payload: {
|
|
67
|
+
error: e instanceof Error ? e.message : String(e),
|
|
68
|
+
context: 'getStacktrace'
|
|
69
|
+
}
|
|
70
|
+
}, '*');
|
|
71
|
+
} catch (postError) {}
|
|
72
|
+
}
|
|
53
73
|
if (void 0 === log.meta.skipFrame) log.meta.skipFrame = 2;
|
|
54
74
|
const logJSON = JSON.stringify(log);
|
|
55
|
-
|
|
56
|
-
|
|
75
|
+
const logForDedup = {
|
|
76
|
+
...log
|
|
77
|
+
};
|
|
78
|
+
delete logForDedup.id;
|
|
79
|
+
const logContentForDedup = JSON.stringify(logForDedup);
|
|
80
|
+
if (lastLogInfo && lastLogInfo.content === logContentForDedup) {
|
|
81
|
+
lastLogInfo.count++;
|
|
82
|
+
log.meta.isDuplicate = true;
|
|
83
|
+
log.meta.duplicateCount = lastLogInfo.count;
|
|
84
|
+
log.meta.duplicateOfId = lastLogInfo.id;
|
|
85
|
+
const updatedLogJSON = JSON.stringify(log);
|
|
86
|
+
try {
|
|
87
|
+
batchLogInfo('info', updatedLogJSON);
|
|
88
|
+
} catch (e) {}
|
|
89
|
+
if (window.parent !== window) try {
|
|
90
|
+
window.parent.postMessage({
|
|
91
|
+
type: 'SELECTED_LOG',
|
|
92
|
+
payload: updatedLogJSON
|
|
93
|
+
}, '*');
|
|
94
|
+
} catch (e) {}
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
lastLogInfo = {
|
|
98
|
+
content: logContentForDedup,
|
|
99
|
+
id: log.id,
|
|
100
|
+
count: 1
|
|
101
|
+
};
|
|
57
102
|
try {
|
|
58
103
|
batchLogInfo('info', logJSON);
|
|
59
104
|
} catch (e) {}
|
|
@@ -70,6 +115,7 @@ async function getStacktrace() {
|
|
|
70
115
|
const frames = mapStacktrace(stacktrace);
|
|
71
116
|
return frames;
|
|
72
117
|
}
|
|
118
|
+
let lastLogInfo = null;
|
|
73
119
|
async function sendTypedLogV2(logWithMeta) {
|
|
74
120
|
sendSelectedLog({
|
|
75
121
|
type: 'typedLogV2',
|
|
@@ -84,7 +130,7 @@ const typedLogInterceptor = (logger)=>({
|
|
|
84
130
|
logger.debug(message, ...args);
|
|
85
131
|
} catch (e) {}
|
|
86
132
|
sendTypedLogV2({
|
|
87
|
-
level: '
|
|
133
|
+
level: 'info',
|
|
88
134
|
args: [
|
|
89
135
|
message,
|
|
90
136
|
...args
|